From 40555f2157922314c347a263db7622b74b823d16 Mon Sep 17 00:00:00 2001 From: Eric Arellano Date: Fri, 22 Mar 2019 11:04:21 -0700 Subject: [PATCH 1/4] Add new test utils to skip test if certain python interpreter --- .../python/interpreter_selection_utils.py | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) 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..30cc21aca32 100644 --- a/tests/python/pants_test/backend/python/interpreter_selection_utils.py +++ b/tests/python/pants_test/backend/python/interpreter_selection_utils.py @@ -5,6 +5,7 @@ from __future__ import absolute_import, division, print_function, unicode_literals import os +import sys from unittest import skipIf from future.utils import PY2 @@ -61,7 +62,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 +72,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 +108,37 @@ 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". + """ + interpreter_major, interpreter_minor = sys.version_info[0:2] + parsed_versions = [version.split(".") for version in versions] + + def version_matches_current_interpreter(major, minor=None): + if int(major) == interpreter_major and minor is None: + return True + return int(major) == interpreter_major and int(minor) == interpreter_minor + + if any(version_matches_current_interpreter(*parsed_version) for parsed_version in parsed_versions): + return skipIf(True, "Current interpreter is one of the specified Python versions.") + return skipIf(False, "Current interpreter") + + +def skip_if_python27(func): + return skip_if_interpreter_is_any_python_version(PY_27)(func) + + +def skip_if_python3(func): + return skip_if_interpreter_is_any_python_version(PY_3)(func) + + +def skip_if_python36(func): + return skip_if_interpreter_is_any_python_version(PY_36)(func) + + +def skip_if_python37(func): + return skip_if_interpreter_is_any_python_version(PY_37)(func) From 0c9e11acb0c357b4d174cfcf56f39dea31a0e88a Mon Sep 17 00:00:00 2001 From: Eric Arellano Date: Fri, 22 Mar 2019 11:09:16 -0700 Subject: [PATCH 2/4] Add docstring --- .../pants_test/backend/python/interpreter_selection_utils.py | 4 ++++ 1 file changed, 4 insertions(+) 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 30cc21aca32..e6f8fa4a854 100644 --- a/tests/python/pants_test/backend/python/interpreter_selection_utils.py +++ b/tests/python/pants_test/backend/python/interpreter_selection_utils.py @@ -129,16 +129,20 @@ def version_matches_current_interpreter(major, minor=None): 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) From b577d5e593a610aeeb9af3cf5ce402bbb8c045cc Mon Sep 17 00:00:00 2001 From: Eric Arellano Date: Fri, 22 Mar 2019 11:13:19 -0700 Subject: [PATCH 3/4] Docstring should use full sentences with periods --- .../backend/python/interpreter_selection_utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 e6f8fa4a854..46dbf63d45c 100644 --- a/tests/python/pants_test/backend/python/interpreter_selection_utils.py +++ b/tests/python/pants_test/backend/python/interpreter_selection_utils.py @@ -129,20 +129,20 @@ def version_matches_current_interpreter(major, minor=None): def skip_if_python27(func): - """A test skip decorator that skips if the current interpreter is Python 2.7""" + """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""" + """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""" + """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""" + """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) From 0bfaaedcaf0d746c355b5813ddcc9d1c2f3841b1 Mon Sep 17 00:00:00 2001 From: Eric Arellano Date: Mon, 25 Mar 2019 12:01:11 -0700 Subject: [PATCH 4/4] Refactor to use packaging.specifiers.SpecifierSet Don't reinvent the wheel --- tests/python/pants_test/backend/python/BUILD | 1 + .../python/interpreter_selection_utils.py | 31 ++++++++++++------- 2 files changed, 21 insertions(+), 11 deletions(-) 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 46dbf63d45c..faf979b20a3 100644 --- a/tests/python/pants_test/backend/python/interpreter_selection_utils.py +++ b/tests/python/pants_test/backend/python/interpreter_selection_utils.py @@ -6,9 +6,11 @@ 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 @@ -115,17 +117,24 @@ def skip_if_interpreter_is_any_python_version(*versions): :param string *versions: Python version strings, such as "2.7", "3". """ - interpreter_major, interpreter_minor = sys.version_info[0:2] - parsed_versions = [version.split(".") for version in versions] - - def version_matches_current_interpreter(major, minor=None): - if int(major) == interpreter_major and minor is None: - return True - return int(major) == interpreter_major and int(minor) == interpreter_minor - - if any(version_matches_current_interpreter(*parsed_version) for parsed_version in parsed_versions): - return skipIf(True, "Current interpreter is one of the specified Python versions.") - return skipIf(False, "Current interpreter") + 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):