We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Python style `checker` pex requires runtime resolution of whl
Post #6618 a new `whl` is published, which is then resolved at runtime to generate a pex that can be subprocessed to check style.

This represents a slightly different model than what occurs currently with plugins, because plugins/backends can be loaded from within a deploy pex. But the `checker` whl/pex (currently) require independent resolution.

To simplify pants release processes, it would be great to allow the `checker` whl to be resolved off the python-path of the pants process itself.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `contrib/python/src/python/pants/contrib/python/checks/tasks/checkstyle/checkstyle.py`
Content:
```
1 # coding=utf-8
2 # Copyright 2015 Pants project contributors (see CONTRIBUTORS.md).
3 # Licensed under the Apache License, Version 2.0 (see LICENSE).
4 
5 from __future__ import absolute_import, division, print_function, unicode_literals
6 
7 import os
8 
9 from pants.backend.python.python_requirement import PythonRequirement
10 from pants.backend.python.subsystems.python_repos import PythonRepos
11 from pants.backend.python.subsystems.python_setup import PythonSetup
12 from pants.backend.python.targets.python_requirement_library import PythonRequirementLibrary
13 from pants.backend.python.targets.python_target import PythonTarget
14 from pants.backend.python.tasks import pex_build_util
15 from pants.base.build_environment import get_buildroot, pants_version
16 from pants.base.exceptions import TaskError
17 from pants.base.hash_utils import hash_all
18 from pants.base.workunit import WorkUnitLabel
19 from pants.build_graph.address import Address
20 from pants.option.custom_types import file_option
21 from pants.task.lint_task_mixin import LintTaskMixin
22 from pants.task.task import Task
23 from pants.util.collections import factory_dict
24 from pants.util.contextutil import temporary_file
25 from pants.util.dirutil import safe_concurrent_creation
26 from pants.util.memo import memoized_classproperty, memoized_property
27 from pex.interpreter import PythonInterpreter
28 from pex.pex import PEX
29 from pex.pex_builder import PEXBuilder
30 
31 from pants.contrib.python.checks.checker import checker
32 from pants.contrib.python.checks.tasks.checkstyle.plugin_subsystem_base import \
33   default_subsystem_for_plugin
34 from pants.contrib.python.checks.tasks.checkstyle.pycodestyle_subsystem import PyCodeStyleSubsystem
35 from pants.contrib.python.checks.tasks.checkstyle.pyflakes_subsystem import FlakeCheckSubsystem
36 
37 
38 class Checkstyle(LintTaskMixin, Task):
39   _PYTHON_SOURCE_EXTENSION = '.py'
40 
41   _CUSTOM_PLUGIN_SUBSYSTEMS = (
42     PyCodeStyleSubsystem,
43     FlakeCheckSubsystem,
44   )
45 
46   @memoized_classproperty
47   def plugin_subsystems(cls):
48     subsystem_type_by_plugin_type = factory_dict(default_subsystem_for_plugin)
49     subsystem_type_by_plugin_type.update((subsystem_type.plugin_type(), subsystem_type)
50                                          for subsystem_type in cls._CUSTOM_PLUGIN_SUBSYSTEMS)
51     return tuple(subsystem_type_by_plugin_type[plugin_type] for plugin_type in checker.plugins())
52 
53   @classmethod
54   def subsystem_dependencies(cls):
55     return super(Task, cls).subsystem_dependencies() + cls.plugin_subsystems + (
56       # Needed implicitly by the pex_build_util functions we use.
57       PythonSetup, PythonRepos)
58 
59   @classmethod
60   def prepare(cls, options, round_manager):
61     round_manager.require_data(PythonInterpreter)
62 
63   @classmethod
64   def register_options(cls, register):
65     super(Checkstyle, cls).register_options(register)
66     register('--severity', fingerprint=True, default='COMMENT', type=str,
67              help='Only messages at this severity or higher are logged. [COMMENT WARNING ERROR].')
68     register('--strict', fingerprint=True, type=bool,
69              help='If enabled, have non-zero exit status for any nit at WARNING or higher.')
70     register('--suppress', fingerprint=True, type=file_option, default=None,
71              help='Takes a text file where specific rules on specific files will be skipped.')
72     register('--fail', fingerprint=True, default=True, type=bool,
73              help='Prevent test failure but still produce output for problems.')
74 
75   def _is_checked(self, target):
76     return (not target.is_synthetic and isinstance(target, PythonTarget) and
77             target.has_sources(self._PYTHON_SOURCE_EXTENSION))
78 
79   _CHECKER_ADDRESS_SPEC = 'contrib/python/src/python/pants/contrib/python/checks/checker'
80   _CHECKER_REQ = 'pantsbuild.pants.contrib.python.checks.checker=={}'.format(pants_version())
81   _CHECKER_ENTRYPOINT = 'pants.contrib.python.checks.checker.checker:main'
82 
83   @memoized_property
84   def checker_target(self):
85     self.context.resolve(self._CHECKER_ADDRESS_SPEC)
86     return self.context.build_graph.get_target(Address.parse(self._CHECKER_ADDRESS_SPEC))
87 
88   def checker_pex(self, interpreter):
89     # TODO(John Sirois): Formalize in pants.base?
90     pants_dev_mode = os.environ.get('PANTS_DEV')
91 
92     if pants_dev_mode:
93       checker_id = self.checker_target.transitive_invalidation_hash()
94     else:
95       checker_id = hash_all([self._CHECKER_REQ])
96 
97     pex_path = os.path.join(self.workdir, 'checker', checker_id, str(interpreter.identity))
98     if not os.path.exists(pex_path):
99       with self.context.new_workunit(name='build-checker'):
100         with safe_concurrent_creation(pex_path) as chroot:
101           builder = PEXBuilder(path=chroot, interpreter=interpreter)
102 
103           if pants_dev_mode:
104             pex_build_util.dump_sources(builder, tgt=self.checker_target, log=self.context.log)
105             req_libs = [tgt for tgt in self.checker_target.closure()
106                         if isinstance(tgt, PythonRequirementLibrary)]
107             pex_build_util.dump_requirement_libs(builder,
108                                                  interpreter=interpreter,
109                                                  req_libs=req_libs,
110                                                  log=self.context.log)
111           else:
112             pex_build_util.dump_requirements(builder,
113                                              interpreter=interpreter,
114                                              reqs=[PythonRequirement(self._CHECKER_REQ)],
115                                              log=self.context.log)
116           builder.set_entry_point(self._CHECKER_ENTRYPOINT)
117           builder.freeze()
118 
119     return PEX(pex_path, interpreter=interpreter)
120 
121   def checkstyle(self, interpreter, sources):
122     """Iterate over sources and run checker on each file.
123 
124     Files can be suppressed with a --suppress option which takes an xml file containing
125     file paths that have exceptions and the plugins they need to ignore.
126 
127     :param sources: iterable containing source file names.
128     :return: (int) number of failures
129     """
130     checker = self.checker_pex(interpreter)
131 
132     args = [
133       '--root-dir={}'.format(get_buildroot()),
134       '--severity={}'.format(self.get_options().severity),
135     ]
136     if self.get_options().suppress:
137       args.append('--suppress={}'.format(self.get_options().suppress))
138     if self.get_options().strict:
139       args.append('--strict')
140 
141     with temporary_file(binary_mode=False) as argfile:
142       for plugin_subsystem in self.plugin_subsystems:
143         options_blob = plugin_subsystem.global_instance().options_blob()
144         if options_blob:
145           argfile.write('--{}-options={}\n'.format(plugin_subsystem.plugin_type().name(),
146                                                    options_blob))
147       argfile.write('\n'.join(sources))
148       argfile.close()
149 
150       args.append('@{}'.format(argfile.name))
151 
152       with self.context.new_workunit(name='pythonstyle',
153                                      labels=[WorkUnitLabel.TOOL, WorkUnitLabel.LINT],
154                                      cmd=' '.join(checker.cmdline(args))) as workunit:
155         failure_count = checker.run(args=args,
156                                     stdout=workunit.output('stdout'),
157                                     stderr=workunit.output('stderr'))
158         if failure_count > 0 and self.get_options().fail:
159           raise TaskError('{} Python Style issues found. You may try `./pants fmt <targets>`'
160                           .format(failure_count))
161         return failure_count
162 
163   def execute(self):
164     """"Run Checkstyle on all found non-synthetic source files."""
165 
166     # If we are linting for Python 3, skip lint altogether.
167     # Long-term Python 3 linting solution tracked by:
168     # https://github.com/pantsbuild/pants/issues/5764
169     interpreter = self.context.products.get_data(PythonInterpreter)
170     # Check interpreter is not 'None' for test cases that do not
171     # run the python interpreter selection task.
172     if interpreter and interpreter.version >= (3, 0, 0):
173       self.context.log.info('Linting is currently disabled for Python 3 targets.\n '
174                             'See https://github.com/pantsbuild/pants/issues/5764 for '
175                             'long-term solution tracking.')
176       return
177 
178     with self.invalidated(self.get_targets(self._is_checked)) as invalidation_check:
179       sources = self.calculate_sources([vt.target for vt in invalidation_check.invalid_vts])
180       if sources:
181         return self.checkstyle(interpreter, sources)
182 
183   def calculate_sources(self, targets):
184     """Generate a set of source files from the given targets."""
185     sources = set()
186     for target in targets:
187       sources.update(
188         source for source in target.sources_relative_to_buildroot()
189         if source.endswith(self._PYTHON_SOURCE_EXTENSION)
190       )
191     return sources
192
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/contrib/python/src/python/pants/contrib/python/checks/tasks/checkstyle/checkstyle.py b/contrib/python/src/python/pants/contrib/python/checks/tasks/checkstyle/checkstyle.py
--- a/contrib/python/src/python/pants/contrib/python/checks/tasks/checkstyle/checkstyle.py
+++ b/contrib/python/src/python/pants/contrib/python/checks/tasks/checkstyle/checkstyle.py
@@ -5,6 +5,7 @@
 from __future__ import absolute_import, division, print_function, unicode_literals
 
 import os
+import sys
 
 from pants.backend.python.python_requirement import PythonRequirement
 from pants.backend.python.subsystems.python_repos import PythonRepos
@@ -27,6 +28,7 @@
 from pex.interpreter import PythonInterpreter
 from pex.pex import PEX
 from pex.pex_builder import PEXBuilder
+from pkg_resources import DistributionNotFound, Requirement, WorkingSet
 
 from pants.contrib.python.checks.checker import checker
 from pants.contrib.python.checks.tasks.checkstyle.plugin_subsystem_base import \
@@ -56,6 +58,10 @@
       # Needed implicitly by the pex_build_util functions we use.
       PythonSetup, PythonRepos)
 
+  @classmethod
+  def implementation_version(cls):
+    return super(Checkstyle, cls).implementation_version() + [('Checkstyle', 0)]
+
   @classmethod
   def prepare(cls, options, round_manager):
     round_manager.require_data(PythonInterpreter)
@@ -109,10 +115,21 @@
                                                  req_libs=req_libs,
                                                  log=self.context.log)
           else:
-            pex_build_util.dump_requirements(builder,
-                                             interpreter=interpreter,
-                                             reqs=[PythonRequirement(self._CHECKER_REQ)],
-                                             log=self.context.log)
+            try:
+              # The checker is already on sys.path, eg: embedded in pants.pex.
+              working_set = WorkingSet(entries=sys.path)
+              for dist in working_set.resolve([Requirement.parse(self._CHECKER_REQ)]):
+                for req in dist.requires():
+                  builder.add_requirement(req)
+                builder.add_distribution(dist)
+              builder.add_requirement(self._CHECKER_REQ)
+            except DistributionNotFound:
+              # We need to resolve the checker from a local or remote distribution repo.
+              pex_build_util.dump_requirements(builder,
+                                               interpreter=interpreter,
+                                               reqs=[PythonRequirement(self._CHECKER_REQ)],
+                                               log=self.context.log)
+
           builder.set_entry_point(self._CHECKER_ENTRYPOINT)
           builder.freeze()

{"golden_diff": "diff --git a/contrib/python/src/python/pants/contrib/python/checks/tasks/checkstyle/checkstyle.py b/contrib/python/src/python/pants/contrib/python/checks/tasks/checkstyle/checkstyle.py\n--- a/contrib/python/src/python/pants/contrib/python/checks/tasks/checkstyle/checkstyle.py\n+++ b/contrib/python/src/python/pants/contrib/python/checks/tasks/checkstyle/checkstyle.py\n@@ -5,6 +5,7 @@\n from __future__ import absolute_import, division, print_function, unicode_literals\n \n import os\n+import sys\n \n from pants.backend.python.python_requirement import PythonRequirement\n from pants.backend.python.subsystems.python_repos import PythonRepos\n@@ -27,6 +28,7 @@\n from pex.interpreter import PythonInterpreter\n from pex.pex import PEX\n from pex.pex_builder import PEXBuilder\n+from pkg_resources import DistributionNotFound, Requirement, WorkingSet\n \n from pants.contrib.python.checks.checker import checker\n from pants.contrib.python.checks.tasks.checkstyle.plugin_subsystem_base import \\\n@@ -56,6 +58,10 @@\n       # Needed implicitly by the pex_build_util functions we use.\n       PythonSetup, PythonRepos)\n \n+  @classmethod\n+  def implementation_version(cls):\n+    return super(Checkstyle, cls).implementation_version() + [('Checkstyle', 0)]\n+\n   @classmethod\n   def prepare(cls, options, round_manager):\n     round_manager.require_data(PythonInterpreter)\n@@ -109,10 +115,21 @@\n                                                  req_libs=req_libs,\n                                                  log=self.context.log)\n           else:\n-            pex_build_util.dump_requirements(builder,\n-                                             interpreter=interpreter,\n-                                             reqs=[PythonRequirement(self._CHECKER_REQ)],\n-                                             log=self.context.log)\n+            try:\n+              # The checker is already on sys.path, eg: embedded in pants.pex.\n+              working_set = WorkingSet(entries=sys.path)\n+              for dist in working_set.resolve([Requirement.parse(self._CHECKER_REQ)]):\n+                for req in dist.requires():\n+                  builder.add_requirement(req)\n+                builder.add_distribution(dist)\n+              builder.add_requirement(self._CHECKER_REQ)\n+            except DistributionNotFound:\n+              # We need to resolve the checker from a local or remote distribution repo.\n+              pex_build_util.dump_requirements(builder,\n+                                               interpreter=interpreter,\n+                                               reqs=[PythonRequirement(self._CHECKER_REQ)],\n+                                               log=self.context.log)\n+\n           builder.set_entry_point(self._CHECKER_ENTRYPOINT)\n           builder.freeze()\n", "issue": "Python style `checker` pex requires runtime resolution of whl\nPost #6618 a new `whl` is published, which is then resolved at runtime to generate a pex that can be subprocessed to check style.\r\n\r\nThis represents a slightly different model than what occurs currently with plugins, because plugins/backends can be loaded from within a deploy pex. But the `checker` whl/pex (currently) require independent resolution.\r\n\r\nTo simplify pants release processes, it would be great to allow the `checker` whl to be resolved off the python-path of the pants process itself.\n", "before_files": [{"content": "# coding=utf-8\n# Copyright 2015 Pants project contributors (see CONTRIBUTORS.md).\n# Licensed under the Apache License, Version 2.0 (see LICENSE).\n\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport os\n\nfrom pants.backend.python.python_requirement import PythonRequirement\nfrom pants.backend.python.subsystems.python_repos import PythonRepos\nfrom pants.backend.python.subsystems.python_setup import PythonSetup\nfrom pants.backend.python.targets.python_requirement_library import PythonRequirementLibrary\nfrom pants.backend.python.targets.python_target import PythonTarget\nfrom pants.backend.python.tasks import pex_build_util\nfrom pants.base.build_environment import get_buildroot, pants_version\nfrom pants.base.exceptions import TaskError\nfrom pants.base.hash_utils import hash_all\nfrom pants.base.workunit import WorkUnitLabel\nfrom pants.build_graph.address import Address\nfrom pants.option.custom_types import file_option\nfrom pants.task.lint_task_mixin import LintTaskMixin\nfrom pants.task.task import Task\nfrom pants.util.collections import factory_dict\nfrom pants.util.contextutil import temporary_file\nfrom pants.util.dirutil import safe_concurrent_creation\nfrom pants.util.memo import memoized_classproperty, memoized_property\nfrom pex.interpreter import PythonInterpreter\nfrom pex.pex import PEX\nfrom pex.pex_builder import PEXBuilder\n\nfrom pants.contrib.python.checks.checker import checker\nfrom pants.contrib.python.checks.tasks.checkstyle.plugin_subsystem_base import \\\n  default_subsystem_for_plugin\nfrom pants.contrib.python.checks.tasks.checkstyle.pycodestyle_subsystem import PyCodeStyleSubsystem\nfrom pants.contrib.python.checks.tasks.checkstyle.pyflakes_subsystem import FlakeCheckSubsystem\n\n\nclass Checkstyle(LintTaskMixin, Task):\n  _PYTHON_SOURCE_EXTENSION = '.py'\n\n  _CUSTOM_PLUGIN_SUBSYSTEMS = (\n    PyCodeStyleSubsystem,\n    FlakeCheckSubsystem,\n  )\n\n  @memoized_classproperty\n  def plugin_subsystems(cls):\n    subsystem_type_by_plugin_type = factory_dict(default_subsystem_for_plugin)\n    subsystem_type_by_plugin_type.update((subsystem_type.plugin_type(), subsystem_type)\n                                         for subsystem_type in cls._CUSTOM_PLUGIN_SUBSYSTEMS)\n    return tuple(subsystem_type_by_plugin_type[plugin_type] for plugin_type in checker.plugins())\n\n  @classmethod\n  def subsystem_dependencies(cls):\n    return super(Task, cls).subsystem_dependencies() + cls.plugin_subsystems + (\n      # Needed implicitly by the pex_build_util functions we use.\n      PythonSetup, PythonRepos)\n\n  @classmethod\n  def prepare(cls, options, round_manager):\n    round_manager.require_data(PythonInterpreter)\n\n  @classmethod\n  def register_options(cls, register):\n    super(Checkstyle, cls).register_options(register)\n    register('--severity', fingerprint=True, default='COMMENT', type=str,\n             help='Only messages at this severity or higher are logged. [COMMENT WARNING ERROR].')\n    register('--strict', fingerprint=True, type=bool,\n             help='If enabled, have non-zero exit status for any nit at WARNING or higher.')\n    register('--suppress', fingerprint=True, type=file_option, default=None,\n             help='Takes a text file where specific rules on specific files will be skipped.')\n    register('--fail', fingerprint=True, default=True, type=bool,\n             help='Prevent test failure but still produce output for problems.')\n\n  def _is_checked(self, target):\n    return (not target.is_synthetic and isinstance(target, PythonTarget) and\n            target.has_sources(self._PYTHON_SOURCE_EXTENSION))\n\n  _CHECKER_ADDRESS_SPEC = 'contrib/python/src/python/pants/contrib/python/checks/checker'\n  _CHECKER_REQ = 'pantsbuild.pants.contrib.python.checks.checker=={}'.format(pants_version())\n  _CHECKER_ENTRYPOINT = 'pants.contrib.python.checks.checker.checker:main'\n\n  @memoized_property\n  def checker_target(self):\n    self.context.resolve(self._CHECKER_ADDRESS_SPEC)\n    return self.context.build_graph.get_target(Address.parse(self._CHECKER_ADDRESS_SPEC))\n\n  def checker_pex(self, interpreter):\n    # TODO(John Sirois): Formalize in pants.base?\n    pants_dev_mode = os.environ.get('PANTS_DEV')\n\n    if pants_dev_mode:\n      checker_id = self.checker_target.transitive_invalidation_hash()\n    else:\n      checker_id = hash_all([self._CHECKER_REQ])\n\n    pex_path = os.path.join(self.workdir, 'checker', checker_id, str(interpreter.identity))\n    if not os.path.exists(pex_path):\n      with self.context.new_workunit(name='build-checker'):\n        with safe_concurrent_creation(pex_path) as chroot:\n          builder = PEXBuilder(path=chroot, interpreter=interpreter)\n\n          if pants_dev_mode:\n            pex_build_util.dump_sources(builder, tgt=self.checker_target, log=self.context.log)\n            req_libs = [tgt for tgt in self.checker_target.closure()\n                        if isinstance(tgt, PythonRequirementLibrary)]\n            pex_build_util.dump_requirement_libs(builder,\n                                                 interpreter=interpreter,\n                                                 req_libs=req_libs,\n                                                 log=self.context.log)\n          else:\n            pex_build_util.dump_requirements(builder,\n                                             interpreter=interpreter,\n                                             reqs=[PythonRequirement(self._CHECKER_REQ)],\n                                             log=self.context.log)\n          builder.set_entry_point(self._CHECKER_ENTRYPOINT)\n          builder.freeze()\n\n    return PEX(pex_path, interpreter=interpreter)\n\n  def checkstyle(self, interpreter, sources):\n    \"\"\"Iterate over sources and run checker on each file.\n\n    Files can be suppressed with a --suppress option which takes an xml file containing\n    file paths that have exceptions and the plugins they need to ignore.\n\n    :param sources: iterable containing source file names.\n    :return: (int) number of failures\n    \"\"\"\n    checker = self.checker_pex(interpreter)\n\n    args = [\n      '--root-dir={}'.format(get_buildroot()),\n      '--severity={}'.format(self.get_options().severity),\n    ]\n    if self.get_options().suppress:\n      args.append('--suppress={}'.format(self.get_options().suppress))\n    if self.get_options().strict:\n      args.append('--strict')\n\n    with temporary_file(binary_mode=False) as argfile:\n      for plugin_subsystem in self.plugin_subsystems:\n        options_blob = plugin_subsystem.global_instance().options_blob()\n        if options_blob:\n          argfile.write('--{}-options={}\\n'.format(plugin_subsystem.plugin_type().name(),\n                                                   options_blob))\n      argfile.write('\\n'.join(sources))\n      argfile.close()\n\n      args.append('@{}'.format(argfile.name))\n\n      with self.context.new_workunit(name='pythonstyle',\n                                     labels=[WorkUnitLabel.TOOL, WorkUnitLabel.LINT],\n                                     cmd=' '.join(checker.cmdline(args))) as workunit:\n        failure_count = checker.run(args=args,\n                                    stdout=workunit.output('stdout'),\n                                    stderr=workunit.output('stderr'))\n        if failure_count > 0 and self.get_options().fail:\n          raise TaskError('{} Python Style issues found. You may try `./pants fmt <targets>`'\n                          .format(failure_count))\n        return failure_count\n\n  def execute(self):\n    \"\"\"\"Run Checkstyle on all found non-synthetic source files.\"\"\"\n\n    # If we are linting for Python 3, skip lint altogether.\n    # Long-term Python 3 linting solution tracked by:\n    # https://github.com/pantsbuild/pants/issues/5764\n    interpreter = self.context.products.get_data(PythonInterpreter)\n    # Check interpreter is not 'None' for test cases that do not\n    # run the python interpreter selection task.\n    if interpreter and interpreter.version >= (3, 0, 0):\n      self.context.log.info('Linting is currently disabled for Python 3 targets.\\n '\n                            'See https://github.com/pantsbuild/pants/issues/5764 for '\n                            'long-term solution tracking.')\n      return\n\n    with self.invalidated(self.get_targets(self._is_checked)) as invalidation_check:\n      sources = self.calculate_sources([vt.target for vt in invalidation_check.invalid_vts])\n      if sources:\n        return self.checkstyle(interpreter, sources)\n\n  def calculate_sources(self, targets):\n    \"\"\"Generate a set of source files from the given targets.\"\"\"\n    sources = set()\n    for target in targets:\n      sources.update(\n        source for source in target.sources_relative_to_buildroot()\n        if source.endswith(self._PYTHON_SOURCE_EXTENSION)\n      )\n    return sources\n", "path": "contrib/python/src/python/pants/contrib/python/checks/tasks/checkstyle/checkstyle.py"}], "after_files": [{"content": "# coding=utf-8\n# Copyright 2015 Pants project contributors (see CONTRIBUTORS.md).\n# Licensed under the Apache License, Version 2.0 (see LICENSE).\n\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport os\nimport sys\n\nfrom pants.backend.python.python_requirement import PythonRequirement\nfrom pants.backend.python.subsystems.python_repos import PythonRepos\nfrom pants.backend.python.subsystems.python_setup import PythonSetup\nfrom pants.backend.python.targets.python_requirement_library import PythonRequirementLibrary\nfrom pants.backend.python.targets.python_target import PythonTarget\nfrom pants.backend.python.tasks import pex_build_util\nfrom pants.base.build_environment import get_buildroot, pants_version\nfrom pants.base.exceptions import TaskError\nfrom pants.base.hash_utils import hash_all\nfrom pants.base.workunit import WorkUnitLabel\nfrom pants.build_graph.address import Address\nfrom pants.option.custom_types import file_option\nfrom pants.task.lint_task_mixin import LintTaskMixin\nfrom pants.task.task import Task\nfrom pants.util.collections import factory_dict\nfrom pants.util.contextutil import temporary_file\nfrom pants.util.dirutil import safe_concurrent_creation\nfrom pants.util.memo import memoized_classproperty, memoized_property\nfrom pex.interpreter import PythonInterpreter\nfrom pex.pex import PEX\nfrom pex.pex_builder import PEXBuilder\nfrom pkg_resources import DistributionNotFound, Requirement, WorkingSet\n\nfrom pants.contrib.python.checks.checker import checker\nfrom pants.contrib.python.checks.tasks.checkstyle.plugin_subsystem_base import \\\n  default_subsystem_for_plugin\nfrom pants.contrib.python.checks.tasks.checkstyle.pycodestyle_subsystem import PyCodeStyleSubsystem\nfrom pants.contrib.python.checks.tasks.checkstyle.pyflakes_subsystem import FlakeCheckSubsystem\n\n\nclass Checkstyle(LintTaskMixin, Task):\n  _PYTHON_SOURCE_EXTENSION = '.py'\n\n  _CUSTOM_PLUGIN_SUBSYSTEMS = (\n    PyCodeStyleSubsystem,\n    FlakeCheckSubsystem,\n  )\n\n  @memoized_classproperty\n  def plugin_subsystems(cls):\n    subsystem_type_by_plugin_type = factory_dict(default_subsystem_for_plugin)\n    subsystem_type_by_plugin_type.update((subsystem_type.plugin_type(), subsystem_type)\n                                         for subsystem_type in cls._CUSTOM_PLUGIN_SUBSYSTEMS)\n    return tuple(subsystem_type_by_plugin_type[plugin_type] for plugin_type in checker.plugins())\n\n  @classmethod\n  def subsystem_dependencies(cls):\n    return super(Task, cls).subsystem_dependencies() + cls.plugin_subsystems + (\n      # Needed implicitly by the pex_build_util functions we use.\n      PythonSetup, PythonRepos)\n\n  @classmethod\n  def implementation_version(cls):\n    return super(Checkstyle, cls).implementation_version() + [('Checkstyle', 0)]\n\n  @classmethod\n  def prepare(cls, options, round_manager):\n    round_manager.require_data(PythonInterpreter)\n\n  @classmethod\n  def register_options(cls, register):\n    super(Checkstyle, cls).register_options(register)\n    register('--severity', fingerprint=True, default='COMMENT', type=str,\n             help='Only messages at this severity or higher are logged. [COMMENT WARNING ERROR].')\n    register('--strict', fingerprint=True, type=bool,\n             help='If enabled, have non-zero exit status for any nit at WARNING or higher.')\n    register('--suppress', fingerprint=True, type=file_option, default=None,\n             help='Takes a text file where specific rules on specific files will be skipped.')\n    register('--fail', fingerprint=True, default=True, type=bool,\n             help='Prevent test failure but still produce output for problems.')\n\n  def _is_checked(self, target):\n    return (not target.is_synthetic and isinstance(target, PythonTarget) and\n            target.has_sources(self._PYTHON_SOURCE_EXTENSION))\n\n  _CHECKER_ADDRESS_SPEC = 'contrib/python/src/python/pants/contrib/python/checks/checker'\n  _CHECKER_REQ = 'pantsbuild.pants.contrib.python.checks.checker=={}'.format(pants_version())\n  _CHECKER_ENTRYPOINT = 'pants.contrib.python.checks.checker.checker:main'\n\n  @memoized_property\n  def checker_target(self):\n    self.context.resolve(self._CHECKER_ADDRESS_SPEC)\n    return self.context.build_graph.get_target(Address.parse(self._CHECKER_ADDRESS_SPEC))\n\n  def checker_pex(self, interpreter):\n    # TODO(John Sirois): Formalize in pants.base?\n    pants_dev_mode = os.environ.get('PANTS_DEV')\n\n    if pants_dev_mode:\n      checker_id = self.checker_target.transitive_invalidation_hash()\n    else:\n      checker_id = hash_all([self._CHECKER_REQ])\n\n    pex_path = os.path.join(self.workdir, 'checker', checker_id, str(interpreter.identity))\n    if not os.path.exists(pex_path):\n      with self.context.new_workunit(name='build-checker'):\n        with safe_concurrent_creation(pex_path) as chroot:\n          builder = PEXBuilder(path=chroot, interpreter=interpreter)\n\n          if pants_dev_mode:\n            pex_build_util.dump_sources(builder, tgt=self.checker_target, log=self.context.log)\n            req_libs = [tgt for tgt in self.checker_target.closure()\n                        if isinstance(tgt, PythonRequirementLibrary)]\n            pex_build_util.dump_requirement_libs(builder,\n                                                 interpreter=interpreter,\n                                                 req_libs=req_libs,\n                                                 log=self.context.log)\n          else:\n            try:\n              # The checker is already on sys.path, eg: embedded in pants.pex.\n              working_set = WorkingSet(entries=sys.path)\n              for dist in working_set.resolve([Requirement.parse(self._CHECKER_REQ)]):\n                for req in dist.requires():\n                  builder.add_requirement(req)\n                builder.add_distribution(dist)\n              builder.add_requirement(self._CHECKER_REQ)\n            except DistributionNotFound:\n              # We need to resolve the checker from a local or remote distribution repo.\n              pex_build_util.dump_requirements(builder,\n                                               interpreter=interpreter,\n                                               reqs=[PythonRequirement(self._CHECKER_REQ)],\n                                               log=self.context.log)\n\n          builder.set_entry_point(self._CHECKER_ENTRYPOINT)\n          builder.freeze()\n\n    return PEX(pex_path, interpreter=interpreter)\n\n  def checkstyle(self, interpreter, sources):\n    \"\"\"Iterate over sources and run checker on each file.\n\n    Files can be suppressed with a --suppress option which takes an xml file containing\n    file paths that have exceptions and the plugins they need to ignore.\n\n    :param sources: iterable containing source file names.\n    :return: (int) number of failures\n    \"\"\"\n    checker = self.checker_pex(interpreter)\n\n    args = [\n      '--root-dir={}'.format(get_buildroot()),\n      '--severity={}'.format(self.get_options().severity),\n    ]\n    if self.get_options().suppress:\n      args.append('--suppress={}'.format(self.get_options().suppress))\n    if self.get_options().strict:\n      args.append('--strict')\n\n    with temporary_file(binary_mode=False) as argfile:\n      for plugin_subsystem in self.plugin_subsystems:\n        options_blob = plugin_subsystem.global_instance().options_blob()\n        if options_blob:\n          argfile.write('--{}-options={}\\n'.format(plugin_subsystem.plugin_type().name(),\n                                                   options_blob))\n      argfile.write('\\n'.join(sources))\n      argfile.close()\n\n      args.append('@{}'.format(argfile.name))\n\n      with self.context.new_workunit(name='pythonstyle',\n                                     labels=[WorkUnitLabel.TOOL, WorkUnitLabel.LINT],\n                                     cmd=' '.join(checker.cmdline(args))) as workunit:\n        failure_count = checker.run(args=args,\n                                    stdout=workunit.output('stdout'),\n                                    stderr=workunit.output('stderr'))\n        if failure_count > 0 and self.get_options().fail:\n          raise TaskError('{} Python Style issues found. You may try `./pants fmt <targets>`'\n                          .format(failure_count))\n        return failure_count\n\n  def execute(self):\n    \"\"\"\"Run Checkstyle on all found non-synthetic source files.\"\"\"\n\n    # If we are linting for Python 3, skip lint altogether.\n    # Long-term Python 3 linting solution tracked by:\n    # https://github.com/pantsbuild/pants/issues/5764\n    interpreter = self.context.products.get_data(PythonInterpreter)\n    # Check interpreter is not 'None' for test cases that do not\n    # run the python interpreter selection task.\n    if interpreter and interpreter.version >= (3, 0, 0):\n      self.context.log.info('Linting is currently disabled for Python 3 targets.\\n '\n                            'See https://github.com/pantsbuild/pants/issues/5764 for '\n                            'long-term solution tracking.')\n      return\n\n    with self.invalidated(self.get_targets(self._is_checked)) as invalidation_check:\n      sources = self.calculate_sources([vt.target for vt in invalidation_check.invalid_vts])\n      if sources:\n        return self.checkstyle(interpreter, sources)\n\n  def calculate_sources(self, targets):\n    \"\"\"Generate a set of source files from the given targets.\"\"\"\n    sources = set()\n    for target in targets:\n      sources.update(\n        source for source in target.sources_relative_to_buildroot()\n        if source.endswith(self._PYTHON_SOURCE_EXTENSION)\n      )\n    return sources\n", "path": "contrib/python/src/python/pants/contrib/python/checks/tasks/checkstyle/checkstyle.py"}]}