diff --git a/tests/python/pants_test/backend/python/BUILD b/tests/python/pants_test/backend/python/BUILD index eee01488e6b..6cc8088b4ef 100644 --- a/tests/python/pants_test/backend/python/BUILD +++ b/tests/python/pants_test/backend/python/BUILD @@ -74,5 +74,6 @@ python_library( dependencies=[ 'src/python/pants/util:process_handler', '3rdparty/python:future', + '3rdparty/python:packaging', ] ) diff --git a/tests/python/pants_test/backend/python/interpreter_selection_utils.py b/tests/python/pants_test/backend/python/interpreter_selection_utils.py index 63d3e358434..faf979b20a3 100644 --- a/tests/python/pants_test/backend/python/interpreter_selection_utils.py +++ b/tests/python/pants_test/backend/python/interpreter_selection_utils.py @@ -5,9 +5,12 @@ from __future__ import absolute_import, division, print_function, unicode_literals import os +import sys +from builtins import map, str from unittest import skipIf from future.utils import PY2 +from packaging.specifiers import SpecifierSet from pants.util.process_handler import subprocess @@ -61,7 +64,7 @@ def python_interpreter_path(version): 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. + :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.') @@ -71,7 +74,7 @@ def skip_unless_any_pythons_present(*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. - :param string *versions: Python version strings, such as 2.7, 3. + :param string *versions: Python version strings, such as "2.7", "3". """ missing_versions = [v for v in versions if not has_python_version(v)] if len(missing_versions) == 1: @@ -107,3 +110,48 @@ def skip_unless_python27_and_python3_present(func): def skip_unless_python27_and_python36_present(func): """A test skip decorator that only runs a test method if python2.7 and python3.6 are present.""" return skip_unless_all_pythons_present(PY_27, PY_36)(func) + + +def skip_if_interpreter_is_any_python_version(*versions): + """A decorator that skips if the current interpreter version is any of the of the specified versions. + + :param string *versions: Python version strings, such as "2.7", "3". + """ + current_interpreter = ".".join(map(str, sys.version_info[0:2])) + # NB: if only the major Python version is specified, e.g. `2` or `3`, we must append `.*` to the string + # for packaging.specifiers.SpecifierSet to work properly. + version_strings = [ + "=={}.*".format(version) if len(version) == 1 else "=={}".format(version) + for version in versions + ] + valid_versions = SpecifierSet(*version_strings) + return ( + skipIf(True, "Current interpreter is one of the specified Python versions.") + if current_interpreter in valid_versions + else skipIf(False, "Current interpreter not one of the specified Python versions.") + ) + + +def skip_if_python2(func): + """A test skip decorator that skips if the current interpreter is Python 2.""" + return skip_if_interpreter_is_any_python_version(PY_2)(func) + + +def skip_if_python27(func): + """A test skip decorator that skips if the current interpreter is Python 2.7.""" + return skip_if_interpreter_is_any_python_version(PY_27)(func) + + +def skip_if_python3(func): + """A test skip decorator that skips if the current interpreter is Python 3.""" + return skip_if_interpreter_is_any_python_version(PY_3)(func) + + +def skip_if_python36(func): + """A test skip decorator that skips if the current interpreter is Python 3.6.""" + return skip_if_interpreter_is_any_python_version(PY_36)(func) + + +def skip_if_python37(func): + """A test skip decorator that skips if the current interpreter is Python 3.7.""" + return skip_if_interpreter_is_any_python_version(PY_37)(func)