Skip to content

Commit

Permalink
Align mypy interpreter constraint with reality. (pantsbuild#7754)
Browse files Browse the repository at this point in the history
The mypy tool actually requires python 3.5+. On a machine with 3.4 and
3.x higher the minimum interpreter selection scheme would pick 3.4 and
fail.

Fixup interpreter constraints to avoid this erroneous error and correct
the corresponding test. Cleanup dead code in
interpreter_selection_utils.py along the way.
  • Loading branch information
jsirois authored May 18, 2019
1 parent 97a6c18 commit 94d6f20
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 34 deletions.
20 changes: 13 additions & 7 deletions contrib/mypy/src/python/pants/contrib/mypy/tasks/mypy_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
class MypyTask(ResolveRequirementsTaskBase):
"""Invoke the mypy static type analyzer for Python."""

_MYPY_COMPATIBLE_INTERPETER_CONSTRAINT = '>=3.5'
_PYTHON_SOURCE_EXTENSION = '.py'

@classmethod
Expand All @@ -48,8 +49,10 @@ def supports_passthru_args(cls):
def subsystem_dependencies(cls):
return super(MypyTask, cls).subsystem_dependencies() + (PythonInterpreterCache,)

def find_py3_interpreter(self):
interpreters = self._interpreter_cache.setup(filters=['>=3'])
def find_mypy_interpreter(self):
interpreters = self._interpreter_cache.setup(
filters=[self._MYPY_COMPATIBLE_INTERPETER_CONSTRAINT]
)
return min(interpreters) if interpreters else None

@staticmethod
Expand Down Expand Up @@ -101,17 +104,20 @@ def _run_mypy(self, py3_interpreter, mypy_args, **kwargs):
return pex.run(mypy_args, **kwargs)

def execute(self):
py3_interpreter = self.find_py3_interpreter()
if not py3_interpreter:
raise TaskError('Unable to find a Python 3.x interpreter (required for mypy).')
mypy_interpreter = self.find_mypy_interpreter()
if not mypy_interpreter:
raise TaskError('Unable to find a Python {} interpreter (required for mypy).'
.format(self._MYPY_COMPATIBLE_INTERPETER_CONSTRAINT))

sources = self._calculate_python_sources(self.context.target_roots)
if not sources:
self.context.log.debug('No Python sources to check.')
return

# Determine interpreter used by the sources so we can tell mypy.
interpreter_for_targets = self._interpreter_cache.select_interpreter_for_targets(self.context.target_roots)
interpreter_for_targets = self._interpreter_cache.select_interpreter_for_targets(
self.context.target_roots
)
if not interpreter_for_targets:
raise TaskError('No Python interpreter compatible with specified sources.')

Expand Down Expand Up @@ -141,7 +147,7 @@ def execute(self):
log_config=WorkUnit.LogConfig(level=self.get_options().level,
colors=self.get_options().colors),
cmd=' '.join(cmd)) as workunit:
returncode = self._run_mypy(py3_interpreter, cmd,
returncode = self._run_mypy(mypy_interpreter, cmd,
env={'MYPYPATH': mypy_path}, stdout=workunit.output('stdout'), stderr=subprocess.STDOUT)
if returncode != 0:
raise TaskError('mypy failed: code={}'.format(returncode))
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from __future__ import absolute_import, division, print_function, unicode_literals

from pants_test.backend.python.interpreter_selection_utils import PY_3, has_python_version
from pants_test.backend.python.interpreter_selection_utils import has_python_version
from pants_test.pants_run_integration_test import PantsRunIntegrationTest


Expand All @@ -16,13 +16,14 @@ def test_mypy(self):
'--',
'--follow-imports=silent'
]
if has_python_version(PY_3):
# Python 3.x is available. Test that we see an error in this integration test.

if any((has_python_version('3.{}'.format(v)) for v in (5, 6, 7, 8))):
# Python 3.5+ is available. Test that we see an error in this integration test.
with self.pants_results(cmd) as pants_run:
self.assert_success(pants_run)
else:
# Python 3.x was not found. Test whether mypy task fails for that reason.
# Python 3.5+ was not found. Test whether mypy task fails for that reason.
with self.pants_results(cmd) as pants_run:
self.assert_failure(pants_run)
self.assertIn('Unable to find a Python 3.x interpreter (required for mypy)',
self.assertIn('Unable to find a Python >=3.5 interpreter (required for mypy)',
pants_run.stdout_data)
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,8 @@
PY_2 = '2'
PY_3 = '3'

PY_26 = '2.6'
PY_27 = '2.7'
PY_34 = '3.4'
PY_35 = '3.5'
PY_36 = '3.6'
PY_37 = '3.7'
PY_38 = '3.8'


def find_all_pythons_present(*versions):
"""Return sorted list of all Python versions present on the system."""
if not versions:
versions = {PY_26, PY_27, PY_34, PY_35, PY_36, PY_37, PY_38}
return sorted(version for version in versions if has_python_version(version))


def has_python_version(version):
Expand Down Expand Up @@ -58,16 +46,6 @@ def python_interpreter_path(version):
return None


def skip_unless_any_pythons_present(*versions):
"""A decorator that only runs the decorated test method if any of the specified pythons are present.
:param string *versions: Python version strings, such as 2.7, 3.
"""
if any(v for v in versions if has_python_version(v)):
return skipIf(False, 'At least one of the expected python versions found.')
return skipIf(True, 'Could not find at least one of the required pythons from {} on the system. Skipping.'.format(versions))


def skip_unless_all_pythons_present(*versions):
"""A decorator that only runs the decorated test method if all of the specified pythons are present.
Expand Down

0 comments on commit 94d6f20

Please sign in to comment.