ansible-test - Clean up old Python 2 compat code (#81962)

* Update generated code __future__ import

* Remove Python 2.x compat from compile sanity test

* Remove __metaclass__ from pylint good names list

* Remove Python 2.x compat from ansible-test injector

* Remove Python 2.x compat from ansible-test importer

* Remove Python 2.x compat from ansible-test units

* Remove Python 2.x compat from validate-modules

* Remove Python 2.x compat from pylint plugins

* Remove more Python 2.x compat from ansible-test

* Remove Python 2.x openssl detection in ansible-test

* Remove obsolete Python 2.x comment

* Remove obsolete ansible-test Python 2.x support

* Remove unused bootstrap script functions

* Keep mypy happy

* Remove unused imports

* Keep pylint happy
pull/81964/head
Matt Clay 8 months ago committed by GitHub
parent 3ae8541133
commit f5c742cdfd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,2 +1 @@
# Empty __init__.py to allow importing of `ansible_test._util.target.common` under Python 2.x. # Empty __init__.py to allow relative imports to work under mypy.
# This allows the ansible-test entry point to report supported Python versions before exiting.

@ -65,7 +65,6 @@ class ContentConfig:
modules: ModulesConfig modules: ModulesConfig
python_versions: tuple[str, ...] python_versions: tuple[str, ...]
py2_support: bool
class EnvironmentConfig(CommonConfig): class EnvironmentConfig(CommonConfig):

@ -29,7 +29,6 @@ from .io import (
from .util import ( from .util import (
ApplicationError, ApplicationError,
display, display,
str_to_version,
) )
from .data import ( from .data import (
@ -75,13 +74,9 @@ def parse_content_config(data: t.Any) -> ContentConfig:
python_versions = tuple(version for version in SUPPORTED_PYTHON_VERSIONS python_versions = tuple(version for version in SUPPORTED_PYTHON_VERSIONS
if version in CONTROLLER_PYTHON_VERSIONS or version in modules.python_versions) if version in CONTROLLER_PYTHON_VERSIONS or version in modules.python_versions)
# True if Python 2.x is supported.
py2_support = any(version for version in python_versions if str_to_version(version)[0] == 2)
return ContentConfig( return ContentConfig(
modules=modules, modules=modules,
python_versions=python_versions, python_versions=python_versions,
py2_support=py2_support,
) )

@ -5,7 +5,6 @@ import base64
import dataclasses import dataclasses
import json import json
import os import os
import re
import typing as t import typing as t
from .encoding import ( from .encoding import (
@ -24,9 +23,7 @@ from .util import (
ApplicationError, ApplicationError,
SubprocessError, SubprocessError,
display, display,
find_executable,
raw_command, raw_command,
str_to_version,
version_to_str, version_to_str,
) )
@ -536,34 +533,12 @@ def get_cryptography_requirements(python: PythonConfig) -> list[str]:
def get_openssl_version(python: PythonConfig) -> t.Optional[tuple[int, ...]]: def get_openssl_version(python: PythonConfig) -> t.Optional[tuple[int, ...]]:
"""Return the openssl version.""" """Return the openssl version."""
if not python.version.startswith('2.'): version = json.loads(raw_command([python.path, os.path.join(ANSIBLE_TEST_TOOLS_ROOT, 'sslcheck.py')], capture=True)[0])['version']
# OpenSSL version checking only works on Python 3.x.
# This should be the most accurate, since it is the Python we will be using.
version = json.loads(raw_command([python.path, os.path.join(ANSIBLE_TEST_TOOLS_ROOT, 'sslcheck.py')], capture=True)[0])['version']
if version: if version:
display.info(f'Detected OpenSSL version {version_to_str(version)} under Python {python.version}.', verbosity=1) display.info(f'Detected OpenSSL version {version_to_str(version)} under Python {python.version}.', verbosity=1)
return tuple(version) return tuple(version)
# Fall back to detecting the OpenSSL version from the CLI.
# This should provide an adequate solution on Python 2.x.
openssl_path = find_executable('openssl', required=False)
if openssl_path:
try:
result = raw_command([openssl_path, 'version'], capture=True)[0]
except SubprocessError:
result = ''
match = re.search(r'^OpenSSL (?P<version>[0-9]+\.[0-9]+\.[0-9]+)', result)
if match:
version = str_to_version(match.group('version'))
display.info(f'Detected OpenSSL version {version_to_str(version)} using the openssl CLI.', verbosity=1)
return version
display.info('Unable to detect OpenSSL version.', verbosity=1) display.info('Unable to detect OpenSSL version.', verbosity=1)

@ -409,7 +409,7 @@ def create_interpreter_wrapper(interpreter: str, injected_interpreter: str) -> N
code = textwrap.dedent(''' code = textwrap.dedent('''
#!%s #!%s
from __future__ import absolute_import from __future__ import annotations
from os import execv from os import execv
from sys import argv from sys import argv

@ -159,7 +159,7 @@ def run_venv(
pip: bool, pip: bool,
path: str, path: str,
) -> bool: ) -> bool:
"""Create a virtual environment using the 'venv' module. Not available on Python 2.x.""" """Create a virtual environment using the 'venv' module."""
cmd = [run_python, '-m', 'venv'] cmd = [run_python, '-m', 'venv']
if system_site_packages: if system_site_packages:

@ -1,2 +1 @@
# Empty __init__.py to allow importing of `ansible_test._util.target.common` under Python 2.x. # Empty __init__.py to keep pylint happy.
# This allows the ansible-test entry point to report supported Python versions before exiting.

@ -35,7 +35,6 @@ bad-names=
tutu, tutu,
good-names= good-names=
__metaclass__,
C, C,
ex, ex,
i, i,

@ -34,7 +34,6 @@ bad-names=
tutu, tutu,
good-names= good-names=
__metaclass__,
C, C,
ex, ex,
i, i,

@ -33,7 +33,6 @@ bad-names=
tutu, tutu,
good-names= good-names=
__metaclass__,
C, C,
ex, ex,
i, i,

@ -32,7 +32,6 @@ except ImportError:
from pylint.checkers import BaseChecker, BaseTokenChecker from pylint.checkers import BaseChecker, BaseTokenChecker
from ansible.module_utils.compat.version import LooseVersion from ansible.module_utils.compat.version import LooseVersion
from ansible.module_utils.six import string_types
from ansible.release import __version__ as ansible_version_raw from ansible.release import __version__ as ansible_version_raw
from ansible.utils.version import SemanticVersion from ansible.utils.version import SemanticVersion
@ -137,7 +136,7 @@ def _get_func_name(node):
def parse_isodate(value): def parse_isodate(value):
"""Parse an ISO 8601 date string.""" """Parse an ISO 8601 date string."""
msg = 'Expected ISO 8601 date string (YYYY-MM-DD)' msg = 'Expected ISO 8601 date string (YYYY-MM-DD)'
if not isinstance(value, string_types): if not isinstance(value, str):
raise ValueError(msg) raise ValueError(msg)
# From Python 3.7 in, there is datetime.date.fromisoformat(). For older versions, # From Python 3.7 in, there is datetime.date.fromisoformat(). For older versions,
# we have to do things manually. # we have to do things manually.

@ -70,7 +70,6 @@ from ansible.module_utils.common.collections import is_iterable
from ansible.module_utils.common.parameters import DEFAULT_TYPE_VALIDATORS from ansible.module_utils.common.parameters import DEFAULT_TYPE_VALIDATORS
from ansible.module_utils.compat.version import StrictVersion, LooseVersion from ansible.module_utils.compat.version import StrictVersion, LooseVersion
from ansible.module_utils.basic import to_bytes from ansible.module_utils.basic import to_bytes
from ansible.module_utils.six import PY3, with_metaclass, string_types
from ansible.plugins.loader import fragment_loader from ansible.plugins.loader import fragment_loader
from ansible.plugins.list import IGNORE as REJECTLIST from ansible.plugins.list import IGNORE as REJECTLIST
from ansible.utils.plugin_docs import add_collection_to_versions_and_dates, add_fragments, get_docstring from ansible.utils.plugin_docs import add_collection_to_versions_and_dates, add_fragments, get_docstring
@ -87,14 +86,11 @@ from .schema import (
from .utils import CaptureStd, NoArgsAnsibleModule, compare_unordered_lists, parse_yaml, parse_isodate from .utils import CaptureStd, NoArgsAnsibleModule, compare_unordered_lists, parse_yaml, parse_isodate
if PY3: # Because there is no ast.TryExcept in Python 3 ast module
# Because there is no ast.TryExcept in Python 3 ast module TRY_EXCEPT = ast.Try
TRY_EXCEPT = ast.Try # REPLACER_WINDOWS from ansible.executor.module_common is byte
# REPLACER_WINDOWS from ansible.executor.module_common is byte # string but we need unicode for Python 3
# string but we need unicode for Python 3 REPLACER_WINDOWS = REPLACER_WINDOWS.decode('utf-8')
REPLACER_WINDOWS = REPLACER_WINDOWS.decode('utf-8')
else:
TRY_EXCEPT = ast.TryExcept
REJECTLIST_DIRS = frozenset(('.git', 'test', '.github', '.idea')) REJECTLIST_DIRS = frozenset(('.git', 'test', '.github', '.idea'))
INDENT_REGEX = re.compile(r'([\t]*)') INDENT_REGEX = re.compile(r'([\t]*)')
@ -269,7 +265,7 @@ class Reporter:
return 3 if sum(ret) else 0 return 3 if sum(ret) else 0
class Validator(with_metaclass(abc.ABCMeta, object)): class Validator(metaclass=abc.ABCMeta):
"""Validator instances are intended to be run on a single object. if you """Validator instances are intended to be run on a single object. if you
are scanning multiple objects for problems, you'll want to have a separate are scanning multiple objects for problems, you'll want to have a separate
Validator for each one.""" Validator for each one."""
@ -1193,7 +1189,7 @@ class ModuleValidator(Validator):
for entry in object: for entry in object:
self._validate_semantic_markup(entry) self._validate_semantic_markup(entry)
return return
if not isinstance(object, string_types): if not isinstance(object, str):
return return
if self.collection: if self.collection:
@ -1374,7 +1370,7 @@ class ModuleValidator(Validator):
continue continue
bad_term = False bad_term = False
for term in check: for term in check:
if not isinstance(term, string_types): if not isinstance(term, str):
msg = name msg = name
if context: if context:
msg += " found in %s" % " -> ".join(context) msg += " found in %s" % " -> ".join(context)
@ -1442,7 +1438,7 @@ class ModuleValidator(Validator):
continue continue
bad_term = False bad_term = False
for term in requirements: for term in requirements:
if not isinstance(term, string_types): if not isinstance(term, str):
msg = "required_if" msg = "required_if"
if context: if context:
msg += " found in %s" % " -> ".join(context) msg += " found in %s" % " -> ".join(context)
@ -1525,13 +1521,13 @@ class ModuleValidator(Validator):
# This is already reported by schema checking # This is already reported by schema checking
return return
for key, value in terms.items(): for key, value in terms.items():
if isinstance(value, string_types): if isinstance(value, str):
value = [value] value = [value]
if not isinstance(value, (list, tuple)): if not isinstance(value, (list, tuple)):
# This is already reported by schema checking # This is already reported by schema checking
continue continue
for term in value: for term in value:
if not isinstance(term, string_types): if not isinstance(term, str):
# This is already reported by schema checking # This is already reported by schema checking
continue continue
if len(set(value)) != len(value) or key in value: if len(set(value)) != len(value) or key in value:

@ -1,2 +1 @@
# Empty __init__.py to allow importing of `ansible_test._util.target.common` under Python 2.x. # Empty __init__.py to keep pylint happy.
# This allows the ansible-test entry point to report supported Python versions before exiting.

@ -1,2 +0,0 @@
# Empty __init__.py to allow importing of `ansible_test._util.target.common` under Python 2.x.
# This allows the ansible-test entry point to report supported Python versions before exiting.

@ -2,6 +2,7 @@
"""Provides an entry point for python scripts and python modules on the controller with the current python interpreter and optional code coverage collection.""" """Provides an entry point for python scripts and python modules on the controller with the current python interpreter and optional code coverage collection."""
from __future__ import annotations from __future__ import annotations
import importlib.util
import os import os
import sys import sys
@ -18,22 +19,7 @@ def main():
if coverage_output: if coverage_output:
args += ['-m', 'coverage.__main__', 'run', '--rcfile', coverage_config] args += ['-m', 'coverage.__main__', 'run', '--rcfile', coverage_config]
else: else:
if sys.version_info >= (3, 4): found = bool(importlib.util.find_spec('coverage'))
# noinspection PyUnresolvedReferences
import importlib.util
# noinspection PyUnresolvedReferences
found = bool(importlib.util.find_spec('coverage'))
else:
# noinspection PyDeprecation
import imp
try:
# noinspection PyDeprecation
imp.find_module('coverage')
found = True
except ImportError:
found = False
if not found: if not found:
sys.exit('ERROR: Could not find `coverage` module. ' sys.exit('ERROR: Could not find `coverage` module. '
@ -61,7 +47,7 @@ def find_program(name, executable): # type: (str, bool) -> str
Raises an exception if the program is not found. Raises an exception if the program is not found.
""" """
path = os.environ.get('PATH', os.path.defpath) path = os.environ.get('PATH', os.path.defpath)
seen = set([os.path.abspath(__file__)]) seen = {os.path.abspath(__file__)}
mode = os.F_OK | os.X_OK if executable else os.F_OK mode = os.F_OK | os.X_OK if executable else os.F_OK
for base in path.split(os.path.pathsep): for base in path.split(os.path.pathsep):

@ -38,9 +38,6 @@ def enable_assertion_rewriting_hook(): # type: () -> None
""" """
import sys import sys
if sys.version_info[0] == 2:
return # Python 2.x is not supported
hook_name = '_pytest.assertion.rewrite.AssertionRewritingHook' hook_name = '_pytest.assertion.rewrite.AssertionRewritingHook'
hooks = [hook for hook in sys.meta_path if hook.__class__.__module__ + '.' + hook.__class__.__qualname__ == hook_name] hooks = [hook for hook in sys.meta_path if hook.__class__.__module__ + '.' + hook.__class__.__qualname__ == hook_name]

@ -5,7 +5,6 @@ import sys
ENCODING = 'utf-8' ENCODING = 'utf-8'
ERRORS = 'replace' ERRORS = 'replace'
Text = type(u'')
def main(): def main():
@ -28,21 +27,14 @@ def compile_source(path):
else: else:
return return
# In some situations offset can be None. This can happen for syntax errors on Python 2.6
# (__future__ import following after a regular import).
offset = offset or 0
result = "%s:%d:%d: %s: %s" % (path, lineno, offset, extype.__name__, safe_message(message)) result = "%s:%d:%d: %s: %s" % (path, lineno, offset, extype.__name__, safe_message(message))
if sys.version_info <= (3,):
result = result.encode(ENCODING, ERRORS)
print(result) print(result)
def safe_message(value): def safe_message(value):
"""Given an input value as text or bytes, return the first non-empty line as text, ensuring it can be round-tripped as UTF-8.""" """Given an input value as str or bytes, return the first non-empty line as str, ensuring it can be round-tripped as UTF-8."""
if isinstance(value, Text): if isinstance(value, str):
value = value.encode(ENCODING, ERRORS) value = value.encode(ENCODING, ERRORS)
value = value.decode(ENCODING, ERRORS) value = value.decode(ENCODING, ERRORS)

@ -541,16 +541,6 @@ def main():
"ignore", "ignore",
"AnsibleCollectionFinder has already been configured") "AnsibleCollectionFinder has already been configured")
if sys.version_info[0] == 2:
warnings.filterwarnings(
"ignore",
"Python 2 is no longer supported by the Python core team. Support for it is now deprecated in cryptography,"
" and will be removed in a future release.")
warnings.filterwarnings(
"ignore",
"Python 2 is no longer supported by the Python core team. Support for it is now deprecated in cryptography,"
" and will be removed in the next release.")
try: try:
yield yield
finally: finally:

@ -65,18 +65,6 @@ install_pip() {
fi fi
} }
pip_install() {
pip_packages="$1"
while true; do
# shellcheck disable=SC2086
"${python_interpreter}" -m pip install --disable-pip-version-check ${pip_packages} \
&& break
echo "Failed to install packages. Sleeping before trying again..."
sleep 10
done
}
bootstrap_remote_alpine() bootstrap_remote_alpine()
{ {
py_pkg_prefix="py3" py_pkg_prefix="py3"
@ -279,17 +267,6 @@ bootstrap_remote_rhel()
esac esac
} }
bootstrap_remote_rhel_pinned_pip_packages()
{
# pin packaging and pyparsing to match the downstream vendored versions
pip_packages="
packaging==20.4
pyparsing==2.4.7
"
pip_install "${pip_packages}"
}
bootstrap_remote_ubuntu() bootstrap_remote_ubuntu()
{ {
py_pkg_prefix="python3" py_pkg_prefix="python3"

Loading…
Cancel
Save