ansible-core 2.17.5rc1__py3-none-any.whl → 2.18.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ansible-core might be problematic. Click here for more details.
- ansible/__main__.py +2 -17
- ansible/cli/__init__.py +3 -15
- ansible/cli/config.py +187 -24
- ansible/cli/console.py +1 -1
- ansible/cli/doc.py +38 -16
- ansible/cli/galaxy.py +3 -49
- ansible/cli/inventory.py +2 -2
- ansible/cli/pull.py +2 -2
- ansible/cli/scripts/ansible_connection_cli_stub.py +1 -10
- ansible/config/base.yml +127 -57
- ansible/config/manager.py +89 -11
- ansible/constants.py +32 -9
- ansible/errors/__init__.py +5 -0
- ansible/executor/interpreter_discovery.py +1 -1
- ansible/executor/play_iterator.py +34 -0
- ansible/executor/playbook_executor.py +1 -4
- ansible/executor/powershell/become_wrapper.ps1 +4 -5
- ansible/executor/powershell/bootstrap_wrapper.ps1 +2 -3
- ansible/executor/powershell/exec_wrapper.ps1 +1 -1
- ansible/executor/powershell/module_manifest.py +2 -2
- ansible/executor/task_executor.py +50 -39
- ansible/executor/task_queue_manager.py +1 -1
- ansible/executor/task_result.py +1 -1
- ansible/galaxy/api.py +3 -4
- ansible/galaxy/collection/__init__.py +21 -10
- ansible/galaxy/collection/concrete_artifact_manager.py +10 -5
- ansible/galaxy/collection/galaxy_api_proxy.py +10 -16
- ansible/galaxy/collection/gpg.py +17 -23
- ansible/galaxy/data/COPYING +7 -0
- ansible/galaxy/data/apb/Dockerfile.j2 +1 -0
- ansible/galaxy/data/apb/Makefile.j2 +1 -0
- ansible/galaxy/data/apb/README.md +7 -3
- ansible/galaxy/data/apb/apb.yml.j2 +1 -0
- ansible/galaxy/data/apb/defaults/main.yml.j2 +1 -0
- ansible/galaxy/data/apb/handlers/main.yml.j2 +1 -0
- ansible/galaxy/data/apb/meta/main.yml.j2 +1 -0
- ansible/galaxy/data/apb/playbooks/deprovision.yml.j2 +1 -0
- ansible/galaxy/data/apb/playbooks/provision.yml.j2 +1 -0
- ansible/galaxy/data/apb/tasks/main.yml.j2 +1 -0
- ansible/galaxy/data/apb/tests/ansible.cfg +1 -0
- ansible/galaxy/data/apb/tests/inventory +1 -0
- ansible/galaxy/data/apb/tests/test.yml.j2 +1 -0
- ansible/galaxy/data/apb/vars/main.yml.j2 +1 -0
- ansible/galaxy/data/collections_galaxy_meta.yml +1 -0
- ansible/galaxy/data/container/defaults/main.yml.j2 +1 -0
- ansible/galaxy/data/container/handlers/main.yml.j2 +1 -0
- ansible/galaxy/data/container/meta/container.yml.j2 +1 -0
- ansible/galaxy/data/container/meta/main.yml.j2 +1 -0
- ansible/galaxy/data/container/tasks/main.yml.j2 +1 -0
- ansible/galaxy/data/container/tests/ansible.cfg +1 -0
- ansible/galaxy/data/container/tests/inventory +1 -0
- ansible/galaxy/data/container/tests/test.yml.j2 +1 -0
- ansible/galaxy/data/container/vars/main.yml.j2 +1 -0
- ansible/galaxy/data/default/collection/README.md.j2 +1 -0
- ansible/galaxy/data/default/collection/galaxy.yml.j2 +1 -0
- ansible/galaxy/data/default/collection/meta/runtime.yml +1 -0
- ansible/galaxy/data/default/collection/plugins/README.md.j2 +1 -0
- ansible/galaxy/data/default/role/defaults/main.yml.j2 +1 -0
- ansible/galaxy/data/default/role/handlers/main.yml.j2 +1 -0
- ansible/galaxy/data/default/role/meta/main.yml.j2 +1 -0
- ansible/galaxy/data/default/role/tasks/main.yml.j2 +1 -0
- ansible/galaxy/data/default/role/tests/inventory +1 -0
- ansible/galaxy/data/default/role/tests/test.yml.j2 +1 -0
- ansible/galaxy/data/default/role/vars/main.yml.j2 +1 -0
- ansible/galaxy/data/network/cliconf_plugins/example.py.j2 +1 -0
- ansible/galaxy/data/network/defaults/main.yml.j2 +1 -0
- ansible/galaxy/data/network/library/example_command.py.j2 +1 -0
- ansible/galaxy/data/network/library/example_config.py.j2 +1 -0
- ansible/galaxy/data/network/library/example_facts.py.j2 +1 -0
- ansible/galaxy/data/network/meta/main.yml.j2 +1 -0
- ansible/galaxy/data/network/module_utils/example.py.j2 +1 -0
- ansible/galaxy/data/network/netconf_plugins/example.py.j2 +1 -0
- ansible/galaxy/data/network/tasks/main.yml.j2 +1 -0
- ansible/galaxy/data/network/terminal_plugins/example.py.j2 +1 -0
- ansible/galaxy/data/network/tests/inventory +1 -0
- ansible/galaxy/data/network/tests/test.yml.j2 +1 -0
- ansible/galaxy/data/network/vars/main.yml.j2 +1 -0
- ansible/galaxy/dependency_resolution/providers.py +3 -3
- ansible/galaxy/role.py +1 -1
- ansible/galaxy/token.py +20 -8
- ansible/keyword_desc.yml +1 -1
- ansible/module_utils/_internal/__init__.py +0 -0
- ansible/module_utils/_internal/_concurrent/__init__.py +0 -0
- ansible/module_utils/_internal/_concurrent/_daemon_threading.py +28 -0
- ansible/module_utils/_internal/_concurrent/_futures.py +21 -0
- ansible/module_utils/ansible_release.py +2 -2
- ansible/module_utils/api.py +2 -2
- ansible/module_utils/basic.py +8 -8
- ansible/module_utils/common/collections.py +1 -1
- ansible/module_utils/common/file.py +0 -6
- ansible/module_utils/common/process.py +22 -9
- ansible/module_utils/common/text/converters.py +5 -8
- ansible/module_utils/common/text/formatters.py +20 -4
- ansible/module_utils/common/validation.py +33 -25
- ansible/module_utils/compat/paramiko.py +6 -1
- ansible/module_utils/compat/selinux.py +2 -2
- ansible/module_utils/connection.py +8 -24
- ansible/module_utils/csharp/Ansible.Become.cs +14 -25
- ansible/module_utils/csharp/Ansible.Process.cs +1 -1
- ansible/module_utils/distro/__init__.py +1 -1
- ansible/module_utils/distro/_distro.py +8 -4
- ansible/module_utils/facts/collector.py +2 -0
- ansible/module_utils/facts/default_collectors.py +3 -1
- ansible/module_utils/facts/hardware/aix.py +54 -52
- ansible/module_utils/facts/hardware/darwin.py +37 -34
- ansible/module_utils/facts/hardware/freebsd.py +55 -15
- ansible/module_utils/facts/hardware/hpux.py +3 -0
- ansible/module_utils/facts/hardware/linux.py +101 -57
- ansible/module_utils/facts/hardware/netbsd.py +3 -0
- ansible/module_utils/facts/hardware/openbsd.py +4 -1
- ansible/module_utils/facts/hardware/sunos.py +7 -1
- ansible/module_utils/facts/network/aix.py +16 -17
- ansible/module_utils/facts/network/fc_wwn.py +4 -1
- ansible/module_utils/facts/network/hpux.py +21 -4
- ansible/module_utils/facts/network/iscsi.py +7 -8
- ansible/module_utils/facts/network/linux.py +0 -2
- ansible/module_utils/facts/other/facter.py +9 -4
- ansible/module_utils/facts/other/ohai.py +5 -5
- ansible/module_utils/facts/packages.py +49 -7
- ansible/module_utils/facts/sysctl.py +33 -31
- ansible/module_utils/facts/system/distribution.py +2 -2
- ansible/module_utils/facts/system/local.py +12 -22
- ansible/module_utils/facts/system/service_mgr.py +3 -1
- ansible/module_utils/facts/system/systemd.py +47 -0
- ansible/module_utils/facts/timeout.py +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 +1 -1
- ansible/module_utils/splitter.py +1 -1
- ansible/modules/add_host.py +1 -1
- ansible/modules/apt.py +43 -32
- ansible/modules/apt_key.py +6 -6
- ansible/modules/apt_repository.py +23 -14
- ansible/modules/assemble.py +7 -2
- ansible/modules/assert.py +4 -4
- ansible/modules/blockinfile.py +3 -6
- ansible/modules/command.py +1 -1
- ansible/modules/copy.py +4 -4
- ansible/modules/cron.py +13 -10
- ansible/modules/deb822_repository.py +16 -17
- ansible/modules/debconf.py +25 -22
- ansible/modules/debug.py +1 -1
- ansible/modules/dnf.py +79 -164
- ansible/modules/dnf5.py +54 -29
- ansible/modules/dpkg_selections.py +2 -2
- ansible/modules/expect.py +2 -2
- ansible/modules/fetch.py +2 -2
- ansible/modules/file.py +5 -3
- ansible/modules/find.py +40 -12
- ansible/modules/gather_facts.py +4 -2
- ansible/modules/get_url.py +29 -24
- ansible/modules/git.py +35 -35
- ansible/modules/group.py +71 -1
- ansible/modules/hostname.py +2 -4
- ansible/modules/include_vars.py +5 -5
- ansible/modules/iptables.py +13 -16
- ansible/modules/known_hosts.py +16 -13
- ansible/modules/lineinfile.py +1 -4
- ansible/modules/meta.py +6 -1
- ansible/modules/mount_facts.py +651 -0
- ansible/modules/package_facts.py +63 -80
- ansible/modules/pause.py +4 -3
- ansible/modules/pip.py +14 -14
- ansible/modules/replace.py +1 -4
- ansible/modules/rpm_key.py +31 -11
- ansible/modules/service.py +8 -8
- ansible/modules/service_facts.py +20 -5
- ansible/modules/set_stats.py +1 -1
- ansible/modules/setup.py +3 -3
- ansible/modules/stat.py +3 -3
- ansible/modules/subversion.py +1 -1
- ansible/modules/systemd.py +16 -10
- ansible/modules/systemd_service.py +16 -10
- ansible/modules/sysvinit.py +4 -4
- ansible/modules/unarchive.py +35 -22
- ansible/modules/uri.py +24 -18
- ansible/modules/user.py +148 -13
- ansible/modules/validate_argument_spec.py +3 -3
- ansible/modules/wait_for_connection.py +2 -1
- ansible/modules/yum_repository.py +136 -179
- ansible/parsing/dataloader.py +2 -2
- ansible/parsing/mod_args.py +11 -10
- ansible/parsing/vault/__init__.py +8 -3
- ansible/parsing/yaml/constructor.py +10 -8
- ansible/parsing/yaml/objects.py +1 -1
- ansible/playbook/base.py +12 -23
- ansible/playbook/helpers.py +4 -0
- ansible/playbook/loop_control.py +8 -0
- ansible/playbook/play.py +4 -22
- ansible/playbook/play_context.py +0 -16
- ansible/playbook/playbook_include.py +2 -2
- ansible/playbook/role/__init__.py +2 -2
- ansible/plugins/__init__.py +2 -0
- ansible/plugins/action/__init__.py +7 -9
- ansible/plugins/action/dnf.py +7 -5
- ansible/plugins/action/package.py +5 -4
- ansible/plugins/action/reboot.py +2 -2
- ansible/plugins/become/__init__.py +1 -1
- ansible/plugins/callback/__init__.py +44 -3
- ansible/plugins/callback/default.py +1 -1
- ansible/plugins/cliconf/__init__.py +1 -1
- ansible/plugins/connection/paramiko_ssh.py +2 -80
- ansible/plugins/connection/psrp.py +33 -82
- ansible/plugins/connection/ssh.py +0 -8
- ansible/plugins/connection/winrm.py +46 -1
- ansible/plugins/doc_fragments/connection_pipelining.py +2 -2
- ansible/plugins/doc_fragments/constructed.py +10 -10
- ansible/plugins/doc_fragments/default_callback.py +8 -8
- ansible/plugins/doc_fragments/files.py +5 -5
- ansible/plugins/doc_fragments/inventory_cache.py +2 -2
- ansible/plugins/doc_fragments/result_format_callback.py +6 -6
- ansible/plugins/doc_fragments/return_common.py +1 -1
- ansible/plugins/doc_fragments/shell_common.py +2 -10
- ansible/plugins/doc_fragments/shell_windows.py +0 -9
- ansible/plugins/doc_fragments/url.py +2 -2
- ansible/plugins/doc_fragments/url_windows.py +4 -5
- ansible/plugins/doc_fragments/validate.py +1 -1
- ansible/plugins/filter/core.py +2 -0
- ansible/plugins/filter/human_to_bytes.yml +9 -0
- ansible/plugins/filter/password_hash.yml +1 -1
- ansible/plugins/filter/strftime.yml +1 -1
- ansible/plugins/filter/to_nice_json.yml +7 -3
- ansible/plugins/filter/to_uuid.yml +1 -1
- ansible/plugins/filter/unique.yml +28 -0
- ansible/plugins/inventory/script.py +1 -1
- ansible/plugins/list.py +1 -1
- ansible/plugins/loader.py +0 -11
- ansible/plugins/lookup/config.py +1 -1
- ansible/plugins/lookup/csvfile.py +21 -9
- ansible/plugins/lookup/env.py +8 -9
- ansible/plugins/lookup/ini.py +10 -1
- ansible/plugins/lookup/random_choice.py +2 -2
- ansible/plugins/lookup/url.py +7 -2
- ansible/plugins/shell/__init__.py +15 -20
- ansible/plugins/shell/powershell.py +9 -6
- ansible/plugins/strategy/__init__.py +18 -7
- ansible/plugins/strategy/linear.py +1 -13
- ansible/plugins/test/core.py +23 -1
- ansible/plugins/test/issubset.yml +1 -1
- ansible/plugins/test/subset.yml +1 -1
- ansible/plugins/test/timedout.yml +20 -0
- ansible/plugins/test/vault_encrypted.yml +6 -6
- ansible/plugins/test/vaulted_file.yml +19 -0
- ansible/release.py +2 -2
- ansible/template/__init__.py +3 -8
- ansible/utils/collection_loader/_collection_finder.py +23 -55
- ansible/utils/display.py +44 -31
- ansible/utils/galaxy.py +1 -1
- ansible/utils/jsonrpc.py +1 -1
- ansible/utils/listify.py +1 -5
- ansible/utils/path.py +3 -0
- ansible/utils/vars.py +18 -27
- ansible/vars/manager.py +7 -150
- ansible/vars/plugins.py +1 -1
- ansible_core-2.18.0rc1.dist-info/Apache-License.txt +202 -0
- {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/METADATA +36 -23
- ansible_core-2.18.0rc1.dist-info/MIT-license.txt +14 -0
- ansible_core-2.18.0rc1.dist-info/PSF-license.txt +48 -0
- {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/RECORD +321 -316
- {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/entry_points.txt +1 -1
- ansible_core-2.18.0rc1.dist-info/simplified_bsd.txt +8 -0
- ansible_test/_data/completion/docker.txt +7 -7
- ansible_test/_data/completion/remote.txt +5 -4
- ansible_test/_data/completion/windows.txt +4 -4
- ansible_test/_data/requirements/ansible-test.txt +1 -2
- ansible_test/_data/requirements/constraints.txt +1 -2
- ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
- ansible_test/_data/requirements/sanity.changelog.in +1 -1
- ansible_test/_data/requirements/sanity.changelog.txt +4 -4
- ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
- ansible_test/_data/requirements/sanity.import.txt +1 -1
- ansible_test/_data/requirements/sanity.integration-aliases.txt +1 -1
- ansible_test/_data/requirements/sanity.pep8.txt +1 -1
- ansible_test/_data/requirements/sanity.pylint.txt +6 -8
- ansible_test/_data/requirements/sanity.runtime-metadata.txt +2 -2
- ansible_test/_data/requirements/sanity.validate-modules.txt +3 -3
- ansible_test/_data/requirements/sanity.yamllint.in +1 -0
- ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
- ansible_test/_internal/ansible_util.py +8 -35
- ansible_test/_internal/ci/azp.py +1 -1
- ansible_test/_internal/classification/__init__.py +0 -2
- ansible_test/_internal/cli/parsers/key_value_parsers.py +3 -0
- ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -1
- ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
- ansible_test/_internal/commands/integration/cloud/nios.py +1 -1
- ansible_test/_internal/commands/sanity/__init__.py +96 -19
- ansible_test/_internal/commands/sanity/pylint.py +20 -24
- ansible_test/_internal/completion.py +2 -0
- ansible_test/_internal/constants.py +0 -1
- ansible_test/_internal/coverage_util.py +1 -2
- ansible_test/_internal/docker_util.py +10 -2
- ansible_test/_internal/encoding.py +4 -4
- ansible_test/_internal/host_configs.py +10 -0
- ansible_test/_internal/host_profiles.py +9 -13
- ansible_test/_internal/pypi_proxy.py +1 -1
- ansible_test/_internal/python_requirements.py +5 -14
- ansible_test/_internal/timeout.py +1 -1
- ansible_test/_internal/util.py +56 -8
- ansible_test/_internal/util_common.py +5 -1
- ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.json +3 -1
- ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +6 -3
- ansible_test/_util/controller/sanity/code-smell/empty-init.json +0 -2
- ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +5 -0
- ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +5 -0
- ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +5 -0
- ansible_test/_util/controller/sanity/pylint/config/collection.cfg +6 -0
- ansible_test/_util/controller/sanity/pylint/config/default.cfg +6 -0
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -19
- ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +3 -4
- ansible_test/_util/controller/sanity/shellcheck/exclude.txt +1 -0
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +67 -2
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +27 -5
- ansible_test/_util/target/cli/ansible_test_cli_stub.py +0 -0
- ansible_test/_util/target/common/constants.py +2 -2
- ansible_test/_util/target/injector/python.py +5 -0
- ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +6 -0
- ansible_test/_util/target/sanity/import/importer.py +1 -1
- ansible_test/_util/target/setup/bootstrap.sh +6 -17
- ansible_test/_util/target/setup/requirements.py +18 -24
- ansible_test/config/config.yml +1 -1
- ansible_core-2.17.5rc1.data/scripts/ansible-test +0 -44
- ansible_test/_data/requirements/sanity.mypy.in +0 -10
- ansible_test/_data/requirements/sanity.mypy.txt +0 -18
- ansible_test/_internal/commands/sanity/mypy.py +0 -274
- ansible_test/_util/controller/sanity/mypy/ansible-core.ini +0 -116
- ansible_test/_util/controller/sanity/mypy/ansible-test.ini +0 -27
- ansible_test/_util/controller/sanity/mypy/modules.ini +0 -92
- ansible_test/_util/controller/sanity/mypy/packaging.ini +0 -20
- {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/COPYING +0 -0
- {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/WHEEL +0 -0
- {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/top_level.txt +0 -0
|
@@ -43,7 +43,6 @@ from ...util import (
|
|
|
43
43
|
|
|
44
44
|
from ...util_common import (
|
|
45
45
|
run_command,
|
|
46
|
-
process_scoped_temporary_file,
|
|
47
46
|
)
|
|
48
47
|
|
|
49
48
|
from ...ansible_util import (
|
|
@@ -87,7 +86,7 @@ class PylintTest(SanitySingleVersion):
|
|
|
87
86
|
return [target for target in targets if os.path.splitext(target.path)[1] == '.py' or is_subdir(target.path, 'bin')]
|
|
88
87
|
|
|
89
88
|
def test(self, args: SanityConfig, targets: SanityTargets, python: PythonConfig) -> TestResult:
|
|
90
|
-
|
|
89
|
+
target_paths = set(target.path for target in self.filter_remote_targets(list(targets.targets)))
|
|
91
90
|
|
|
92
91
|
plugin_dir = os.path.join(SANITY_ROOT, 'pylint', 'plugins')
|
|
93
92
|
plugin_names = sorted(p[0] for p in [
|
|
@@ -115,7 +114,13 @@ class PylintTest(SanitySingleVersion):
|
|
|
115
114
|
def add_context(available_paths: set[str], context_name: str, context_filter: c.Callable[[str], bool]) -> None:
|
|
116
115
|
"""Add the specified context to the context list, consuming available paths that match the given context filter."""
|
|
117
116
|
filtered_paths = set(p for p in available_paths if context_filter(p))
|
|
118
|
-
|
|
117
|
+
|
|
118
|
+
if selected_paths := sorted(path for path in filtered_paths if path in target_paths):
|
|
119
|
+
contexts.append((context_name, True, selected_paths))
|
|
120
|
+
|
|
121
|
+
if selected_paths := sorted(path for path in filtered_paths if path not in target_paths):
|
|
122
|
+
contexts.append((context_name, False, selected_paths))
|
|
123
|
+
|
|
119
124
|
available_paths -= filtered_paths
|
|
120
125
|
|
|
121
126
|
def filter_path(path_filter: str = None) -> c.Callable[[str], bool]:
|
|
@@ -166,12 +171,12 @@ class PylintTest(SanitySingleVersion):
|
|
|
166
171
|
|
|
167
172
|
test_start = datetime.datetime.now(tz=datetime.timezone.utc)
|
|
168
173
|
|
|
169
|
-
for context, context_paths in sorted(contexts):
|
|
174
|
+
for context, is_target, context_paths in sorted(contexts):
|
|
170
175
|
if not context_paths:
|
|
171
176
|
continue
|
|
172
177
|
|
|
173
178
|
context_start = datetime.datetime.now(tz=datetime.timezone.utc)
|
|
174
|
-
messages += self.pylint(args, context, context_paths, plugin_dir, plugin_names, python, collection_detail
|
|
179
|
+
messages += self.pylint(args, context, is_target, context_paths, plugin_dir, plugin_names, python, collection_detail)
|
|
175
180
|
context_end = datetime.datetime.now(tz=datetime.timezone.utc)
|
|
176
181
|
|
|
177
182
|
context_times.append('%s: %d (%s)' % (context, len(context_paths), context_end - context_start))
|
|
@@ -202,32 +207,16 @@ class PylintTest(SanitySingleVersion):
|
|
|
202
207
|
|
|
203
208
|
return SanitySuccess(self.name)
|
|
204
209
|
|
|
205
|
-
def create_min_python_db(self, args: SanityConfig, targets: t.Iterable[TestTarget]) -> str:
|
|
206
|
-
"""Create a database of target file paths and their minimum required Python version, returning the path to the database."""
|
|
207
|
-
target_paths = set(target.path for target in self.filter_remote_targets(list(targets)))
|
|
208
|
-
controller_min_version = CONTROLLER_PYTHON_VERSIONS[0]
|
|
209
|
-
target_min_version = REMOTE_ONLY_PYTHON_VERSIONS[0]
|
|
210
|
-
min_python_versions = {
|
|
211
|
-
os.path.abspath(target.path): target_min_version if target.path in target_paths else controller_min_version for target in targets
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
min_python_version_db_path = process_scoped_temporary_file(args)
|
|
215
|
-
|
|
216
|
-
with open(min_python_version_db_path, 'w') as database_file:
|
|
217
|
-
json.dump(min_python_versions, database_file)
|
|
218
|
-
|
|
219
|
-
return min_python_version_db_path
|
|
220
|
-
|
|
221
210
|
@staticmethod
|
|
222
211
|
def pylint(
|
|
223
212
|
args: SanityConfig,
|
|
224
213
|
context: str,
|
|
214
|
+
is_target: bool,
|
|
225
215
|
paths: list[str],
|
|
226
216
|
plugin_dir: str,
|
|
227
217
|
plugin_names: list[str],
|
|
228
218
|
python: PythonConfig,
|
|
229
219
|
collection_detail: CollectionDetail,
|
|
230
|
-
min_python_version_db_path: str,
|
|
231
220
|
) -> list[dict[str, str]]:
|
|
232
221
|
"""Run pylint using the config specified by the context on the specified paths."""
|
|
233
222
|
rcfile = os.path.join(SANITY_ROOT, 'pylint', 'config', context.split('/')[0] + '.cfg')
|
|
@@ -249,6 +238,13 @@ class PylintTest(SanitySingleVersion):
|
|
|
249
238
|
disable_plugins = set(i.strip() for i in config.get('disable-plugins', '').split(',') if i)
|
|
250
239
|
load_plugins = set(plugin_names + ['pylint.extensions.mccabe']) - disable_plugins
|
|
251
240
|
|
|
241
|
+
if is_target:
|
|
242
|
+
context_label = 'target'
|
|
243
|
+
min_python_version = REMOTE_ONLY_PYTHON_VERSIONS[0]
|
|
244
|
+
else:
|
|
245
|
+
context_label = 'controller'
|
|
246
|
+
min_python_version = CONTROLLER_PYTHON_VERSIONS[0]
|
|
247
|
+
|
|
252
248
|
cmd = [
|
|
253
249
|
python.path,
|
|
254
250
|
'-m', 'pylint',
|
|
@@ -259,7 +255,7 @@ class PylintTest(SanitySingleVersion):
|
|
|
259
255
|
'--rcfile', rcfile,
|
|
260
256
|
'--output-format', 'json',
|
|
261
257
|
'--load-plugins', ','.join(sorted(load_plugins)),
|
|
262
|
-
'--
|
|
258
|
+
'--py-version', min_python_version,
|
|
263
259
|
] + paths # fmt: skip
|
|
264
260
|
|
|
265
261
|
if data_context().content.collection:
|
|
@@ -286,7 +282,7 @@ class PylintTest(SanitySingleVersion):
|
|
|
286
282
|
env.update(PYLINTHOME=pylint_home)
|
|
287
283
|
|
|
288
284
|
if paths:
|
|
289
|
-
display.info('Checking
|
|
285
|
+
display.info(f'Checking {len(paths)} file(s) in context {context!r} ({context_label}) with config: {rcfile}', verbosity=1)
|
|
290
286
|
|
|
291
287
|
try:
|
|
292
288
|
stdout, stderr = run_command(args, cmd, env=env, capture=True)
|
|
@@ -246,6 +246,8 @@ class PosixRemoteCompletionConfig(RemoteCompletionConfig, PythonCompletionConfig
|
|
|
246
246
|
class WindowsRemoteCompletionConfig(RemoteCompletionConfig):
|
|
247
247
|
"""Configuration for remote Windows platforms."""
|
|
248
248
|
|
|
249
|
+
connection: str = ''
|
|
250
|
+
|
|
249
251
|
|
|
250
252
|
TCompletionConfig = t.TypeVar('TCompletionConfig', bound=CompletionConfig)
|
|
251
253
|
|
|
@@ -37,7 +37,6 @@ SECCOMP_CHOICES = [
|
|
|
37
37
|
ANSIBLE_BIN_SYMLINK_MAP = {
|
|
38
38
|
'ansible': '../lib/ansible/cli/adhoc.py',
|
|
39
39
|
'ansible-config': '../lib/ansible/cli/config.py',
|
|
40
|
-
'ansible-connection': '../lib/ansible/cli/scripts/ansible_connection_cli_stub.py',
|
|
41
40
|
'ansible-console': '../lib/ansible/cli/console.py',
|
|
42
41
|
'ansible-doc': '../lib/ansible/cli/doc.py',
|
|
43
42
|
'ansible-galaxy': '../lib/ansible/cli/galaxy.py',
|
|
@@ -69,8 +69,7 @@ class CoverageVersion:
|
|
|
69
69
|
|
|
70
70
|
COVERAGE_VERSIONS = (
|
|
71
71
|
# IMPORTANT: Keep this in sync with the ansible-test.txt requirements file.
|
|
72
|
-
CoverageVersion('7.
|
|
73
|
-
CoverageVersion('6.5.0', 7, (3, 7), (3, 7)),
|
|
72
|
+
CoverageVersion('7.6.1', 7, (3, 8), (3, 13)),
|
|
74
73
|
)
|
|
75
74
|
"""
|
|
76
75
|
This tuple specifies the coverage version to use for Python version ranges.
|
|
@@ -20,6 +20,8 @@ from .util import (
|
|
|
20
20
|
SubprocessError,
|
|
21
21
|
cache,
|
|
22
22
|
OutputStream,
|
|
23
|
+
InternalError,
|
|
24
|
+
format_command_output,
|
|
23
25
|
)
|
|
24
26
|
|
|
25
27
|
from .util_common import (
|
|
@@ -47,7 +49,7 @@ DOCKER_COMMANDS = [
|
|
|
47
49
|
'podman',
|
|
48
50
|
]
|
|
49
51
|
|
|
50
|
-
UTILITY_IMAGE = 'quay.io/ansible/ansible-test-utility-container:
|
|
52
|
+
UTILITY_IMAGE = 'quay.io/ansible/ansible-test-utility-container:3.1.0'
|
|
51
53
|
|
|
52
54
|
# Max number of open files in a docker container.
|
|
53
55
|
# Passed with --ulimit option to the docker run command.
|
|
@@ -300,7 +302,7 @@ def detect_host_properties(args: CommonConfig) -> ContainerHostProperties:
|
|
|
300
302
|
options = ['--volume', '/sys/fs/cgroup:/probe:ro']
|
|
301
303
|
cmd = ['sh', '-c', ' && echo "-" && '.join(multi_line_commands)]
|
|
302
304
|
|
|
303
|
-
stdout = run_utility_container(args, 'ansible-test-probe', cmd, options)
|
|
305
|
+
stdout, stderr = run_utility_container(args, 'ansible-test-probe', cmd, options)
|
|
304
306
|
|
|
305
307
|
if args.explain:
|
|
306
308
|
return ContainerHostProperties(
|
|
@@ -313,6 +315,12 @@ def detect_host_properties(args: CommonConfig) -> ContainerHostProperties:
|
|
|
313
315
|
|
|
314
316
|
blocks = stdout.split('\n-\n')
|
|
315
317
|
|
|
318
|
+
if len(blocks) != len(multi_line_commands):
|
|
319
|
+
message = f'Unexpected probe output. Expected {len(multi_line_commands)} blocks but found {len(blocks)}.\n'
|
|
320
|
+
message += format_command_output(stdout, stderr)
|
|
321
|
+
|
|
322
|
+
raise InternalError(message.strip())
|
|
323
|
+
|
|
316
324
|
values = blocks[0].split('\n')
|
|
317
325
|
|
|
318
326
|
audit_parts = values[0].split(' ', 1)
|
|
@@ -6,17 +6,17 @@ import typing as t
|
|
|
6
6
|
ENCODING = 'utf-8'
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
def to_optional_bytes(value: t.Optional[
|
|
9
|
+
def to_optional_bytes(value: t.Optional[str | bytes], errors: str = 'strict') -> t.Optional[bytes]:
|
|
10
10
|
"""Return the given value as bytes encoded using UTF-8 if not already bytes, or None if the value is None."""
|
|
11
11
|
return None if value is None else to_bytes(value, errors)
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
def to_optional_text(value: t.Optional[
|
|
14
|
+
def to_optional_text(value: t.Optional[str | bytes], errors: str = 'strict') -> t.Optional[str]:
|
|
15
15
|
"""Return the given value as text decoded using UTF-8 if not already text, or None if the value is None."""
|
|
16
16
|
return None if value is None else to_text(value, errors)
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
def to_bytes(value:
|
|
19
|
+
def to_bytes(value: str | bytes, errors: str = 'strict') -> bytes:
|
|
20
20
|
"""Return the given value as bytes encoded using UTF-8 if not already bytes."""
|
|
21
21
|
if isinstance(value, bytes):
|
|
22
22
|
return value
|
|
@@ -27,7 +27,7 @@ def to_bytes(value: t.AnyStr, errors: str = 'strict') -> bytes:
|
|
|
27
27
|
raise Exception('value is not bytes or text: %s' % type(value))
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
def to_text(value:
|
|
30
|
+
def to_text(value: str | bytes, errors: str = 'strict') -> str:
|
|
31
31
|
"""Return the given value as text decoded using UTF-8 if not already text."""
|
|
32
32
|
if isinstance(value, bytes):
|
|
33
33
|
return value.decode(ENCODING, errors)
|
|
@@ -399,10 +399,20 @@ class WindowsConfig(HostConfig, metaclass=abc.ABCMeta):
|
|
|
399
399
|
class WindowsRemoteConfig(RemoteConfig, WindowsConfig):
|
|
400
400
|
"""Configuration for a remote Windows host."""
|
|
401
401
|
|
|
402
|
+
connection: t.Optional[str] = None
|
|
403
|
+
|
|
402
404
|
def get_defaults(self, context: HostContext) -> WindowsRemoteCompletionConfig:
|
|
403
405
|
"""Return the default settings."""
|
|
404
406
|
return filter_completion(windows_completion()).get(self.name) or windows_completion().get(self.platform)
|
|
405
407
|
|
|
408
|
+
def apply_defaults(self, context: HostContext, defaults: CompletionConfig) -> None:
|
|
409
|
+
"""Apply default settings."""
|
|
410
|
+
assert isinstance(defaults, WindowsRemoteCompletionConfig)
|
|
411
|
+
|
|
412
|
+
super().apply_defaults(context, defaults)
|
|
413
|
+
|
|
414
|
+
self.connection = self.connection or defaults.connection
|
|
415
|
+
|
|
406
416
|
|
|
407
417
|
@dataclasses.dataclass
|
|
408
418
|
class WindowsInventoryConfig(InventoryConfig, WindowsConfig):
|
|
@@ -56,6 +56,7 @@ from .util import (
|
|
|
56
56
|
InternalError,
|
|
57
57
|
HostConnectionError,
|
|
58
58
|
ANSIBLE_TEST_TARGET_ROOT,
|
|
59
|
+
WINDOWS_CONNECTION_VARIABLES,
|
|
59
60
|
)
|
|
60
61
|
|
|
61
62
|
from .util_common import (
|
|
@@ -1367,23 +1368,18 @@ class WindowsRemoteProfile(RemoteProfile[WindowsRemoteConfig]):
|
|
|
1367
1368
|
connection = core_ci.connection
|
|
1368
1369
|
|
|
1369
1370
|
variables: dict[str, t.Optional[t.Union[str, int]]] = dict(
|
|
1370
|
-
ansible_connection='winrm',
|
|
1371
|
-
ansible_pipelining='yes',
|
|
1372
|
-
ansible_winrm_server_cert_validation='ignore',
|
|
1373
1371
|
ansible_host=connection.hostname,
|
|
1374
|
-
ansible_port
|
|
1372
|
+
# ansible_port is intentionally not set using connection.port -- connection-specific variables can set this instead
|
|
1375
1373
|
ansible_user=connection.username,
|
|
1376
|
-
|
|
1377
|
-
|
|
1374
|
+
ansible_ssh_private_key_file=core_ci.ssh_key.key, # required for scenarios which change the connection plugin to SSH
|
|
1375
|
+
ansible_test_connection_password=connection.password, # required for scenarios which change the connection plugin to require a password
|
|
1378
1376
|
)
|
|
1379
1377
|
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
ansible_port='5985',
|
|
1386
|
-
)
|
|
1378
|
+
variables.update(ansible_connection=self.config.connection.split('+')[0])
|
|
1379
|
+
variables.update(WINDOWS_CONNECTION_VARIABLES[self.config.connection])
|
|
1380
|
+
|
|
1381
|
+
if variables.pop('use_password'):
|
|
1382
|
+
variables.update(ansible_password=connection.password)
|
|
1387
1383
|
|
|
1388
1384
|
return variables
|
|
1389
1385
|
|
|
@@ -69,7 +69,7 @@ def run_pypi_proxy(args: EnvironmentConfig, targets_use_pypi: bool) -> None:
|
|
|
69
69
|
display.warning('Unable to use the PyPI proxy because Docker is not available. Installation of packages using `pip` may fail.')
|
|
70
70
|
return
|
|
71
71
|
|
|
72
|
-
image = 'quay.io/ansible/pypi-test-container:3.
|
|
72
|
+
image = 'quay.io/ansible/pypi-test-container:3.2.0'
|
|
73
73
|
port = 3141
|
|
74
74
|
|
|
75
75
|
run_support_container(
|
|
@@ -112,6 +112,8 @@ class PipBootstrap(PipCommand):
|
|
|
112
112
|
|
|
113
113
|
pip_version: str
|
|
114
114
|
packages: list[str]
|
|
115
|
+
setuptools: bool
|
|
116
|
+
wheel: bool
|
|
115
117
|
|
|
116
118
|
|
|
117
119
|
# Entry Points
|
|
@@ -177,6 +179,8 @@ def collect_bootstrap(python: PythonConfig) -> list[PipCommand]:
|
|
|
177
179
|
bootstrap = PipBootstrap(
|
|
178
180
|
pip_version=pip_version,
|
|
179
181
|
packages=packages,
|
|
182
|
+
setuptools=False,
|
|
183
|
+
wheel=False,
|
|
180
184
|
)
|
|
181
185
|
|
|
182
186
|
return [bootstrap]
|
|
@@ -218,17 +222,6 @@ def collect_requirements(
|
|
|
218
222
|
# removing them reduces the size of environments cached in containers
|
|
219
223
|
uninstall_packages = list(get_venv_packages(python))
|
|
220
224
|
|
|
221
|
-
if not minimize:
|
|
222
|
-
# installed packages may have run-time dependencies on setuptools
|
|
223
|
-
uninstall_packages.remove('setuptools')
|
|
224
|
-
|
|
225
|
-
# hack to allow the package-data sanity test to keep wheel in the venv
|
|
226
|
-
install_commands = [command for command in commands if isinstance(command, PipInstall)]
|
|
227
|
-
install_wheel = any(install.has_package('wheel') for install in install_commands)
|
|
228
|
-
|
|
229
|
-
if install_wheel:
|
|
230
|
-
uninstall_packages.remove('wheel')
|
|
231
|
-
|
|
232
225
|
commands.extend(collect_uninstall(packages=uninstall_packages))
|
|
233
226
|
|
|
234
227
|
return commands
|
|
@@ -412,9 +405,7 @@ def get_venv_packages(python: PythonConfig) -> dict[str, str]:
|
|
|
412
405
|
# See: https://github.com/ansible/base-test-container/blob/main/files/installer.py
|
|
413
406
|
|
|
414
407
|
default_packages = dict(
|
|
415
|
-
pip='
|
|
416
|
-
setuptools='67.7.2',
|
|
417
|
-
wheel='0.37.1',
|
|
408
|
+
pip='24.2',
|
|
418
409
|
)
|
|
419
410
|
|
|
420
411
|
override_packages: dict[str, dict[str, str]] = {
|
|
@@ -118,7 +118,7 @@ def configure_test_timeout(args: TestConfig) -> None:
|
|
|
118
118
|
|
|
119
119
|
raise TimeoutExpiredError(f'Tests aborted after exceeding the {timeout.duration} minute time limit.')
|
|
120
120
|
|
|
121
|
-
def timeout_waiter(timeout_seconds:
|
|
121
|
+
def timeout_waiter(timeout_seconds: float) -> None:
|
|
122
122
|
"""Background thread which will kill the current process if the timeout elapses."""
|
|
123
123
|
time.sleep(timeout_seconds)
|
|
124
124
|
os.kill(os.getpid(), signal.SIGUSR1)
|
ansible_test/_internal/util.py
CHANGED
|
@@ -134,6 +134,46 @@ class Architecture:
|
|
|
134
134
|
REMOTE_ARCHITECTURES = list(value for key, value in Architecture.__dict__.items() if not key.startswith('__'))
|
|
135
135
|
|
|
136
136
|
|
|
137
|
+
WINDOWS_CONNECTION_VARIABLES: dict[str, t.Any] = {
|
|
138
|
+
'psrp+http': dict(
|
|
139
|
+
ansible_port=5985,
|
|
140
|
+
ansible_psrp_protocol='http',
|
|
141
|
+
use_password=True,
|
|
142
|
+
),
|
|
143
|
+
'psrp+https': dict(
|
|
144
|
+
ansible_port=5986,
|
|
145
|
+
ansible_psrp_protocol='https',
|
|
146
|
+
ansible_psrp_cert_validation='ignore',
|
|
147
|
+
use_password=True,
|
|
148
|
+
),
|
|
149
|
+
'ssh+key': dict(
|
|
150
|
+
ansible_port=22,
|
|
151
|
+
ansible_shell_type='powershell',
|
|
152
|
+
use_password=False,
|
|
153
|
+
),
|
|
154
|
+
'ssh+password': dict(
|
|
155
|
+
ansible_port=22,
|
|
156
|
+
ansible_shell_type='powershell',
|
|
157
|
+
use_password=True,
|
|
158
|
+
),
|
|
159
|
+
'winrm+http': dict(
|
|
160
|
+
ansible_port=5985,
|
|
161
|
+
ansible_winrm_scheme='http',
|
|
162
|
+
ansible_winrm_transport='ntlm',
|
|
163
|
+
use_password=True,
|
|
164
|
+
),
|
|
165
|
+
'winrm+https': dict(
|
|
166
|
+
ansible_port=5986,
|
|
167
|
+
ansible_winrm_scheme='https',
|
|
168
|
+
ansible_winrm_server_cert_validation='ignore',
|
|
169
|
+
use_password=True,
|
|
170
|
+
),
|
|
171
|
+
}
|
|
172
|
+
"""Dictionary of Windows connection types and variables required to use them."""
|
|
173
|
+
|
|
174
|
+
WINDOWS_CONNECTIONS = list(WINDOWS_CONNECTION_VARIABLES)
|
|
175
|
+
|
|
176
|
+
|
|
137
177
|
def is_valid_identifier(value: str) -> bool:
|
|
138
178
|
"""Return True if the given value is a valid non-keyword Python identifier, otherwise return False."""
|
|
139
179
|
return value.isidentifier() and not keyword.iskeyword(value)
|
|
@@ -930,14 +970,7 @@ class SubprocessError(ApplicationError):
|
|
|
930
970
|
error_callback: t.Optional[c.Callable[[SubprocessError], None]] = None,
|
|
931
971
|
) -> None:
|
|
932
972
|
message = 'Command "%s" returned exit status %s.\n' % (shlex.join(cmd), status)
|
|
933
|
-
|
|
934
|
-
if stderr:
|
|
935
|
-
message += '>>> Standard Error\n'
|
|
936
|
-
message += '%s%s\n' % (stderr.strip(), Display.clear)
|
|
937
|
-
|
|
938
|
-
if stdout:
|
|
939
|
-
message += '>>> Standard Output\n'
|
|
940
|
-
message += '%s%s\n' % (stdout.strip(), Display.clear)
|
|
973
|
+
message += format_command_output(stdout, stderr)
|
|
941
974
|
|
|
942
975
|
self.cmd = cmd
|
|
943
976
|
self.message = message
|
|
@@ -981,6 +1014,21 @@ class HostConnectionError(ApplicationError):
|
|
|
981
1014
|
self._callback()
|
|
982
1015
|
|
|
983
1016
|
|
|
1017
|
+
def format_command_output(stdout: str, stderr: str) -> str:
|
|
1018
|
+
"""Return a formatted string containing the given stdout and stderr (if any)."""
|
|
1019
|
+
message = ''
|
|
1020
|
+
|
|
1021
|
+
if stderr := stderr.strip():
|
|
1022
|
+
message += '>>> Standard Error\n'
|
|
1023
|
+
message += f'{stderr}{Display.clear}\n'
|
|
1024
|
+
|
|
1025
|
+
if stdout := stdout.strip():
|
|
1026
|
+
message += '>>> Standard Output\n'
|
|
1027
|
+
message += f'{stdout}{Display.clear}\n'
|
|
1028
|
+
|
|
1029
|
+
return message
|
|
1030
|
+
|
|
1031
|
+
|
|
984
1032
|
def retry(func: t.Callable[..., TValue], ex_type: t.Type[BaseException] = SubprocessError, sleep: int = 10, attempts: int = 10, warn: bool = True) -> TValue:
|
|
985
1033
|
"""Retry the specified function on failure."""
|
|
986
1034
|
for dummy in range(1, attempts):
|
|
@@ -269,7 +269,10 @@ def named_temporary_file(args: CommonConfig, prefix: str, suffix: str, directory
|
|
|
269
269
|
tempfile_fd.write(to_bytes(content))
|
|
270
270
|
tempfile_fd.flush()
|
|
271
271
|
|
|
272
|
-
|
|
272
|
+
try:
|
|
273
|
+
yield tempfile_fd.name
|
|
274
|
+
finally:
|
|
275
|
+
pass
|
|
273
276
|
|
|
274
277
|
|
|
275
278
|
def write_json_test_results(
|
|
@@ -300,6 +303,7 @@ def get_injector_path() -> str:
|
|
|
300
303
|
injector_names = sorted(list(ANSIBLE_BIN_SYMLINK_MAP) + [
|
|
301
304
|
'importer.py',
|
|
302
305
|
'pytest',
|
|
306
|
+
'ansible_connection_cli_stub.py',
|
|
303
307
|
])
|
|
304
308
|
|
|
305
309
|
scripts = (
|
|
@@ -28,13 +28,13 @@ def main():
|
|
|
28
28
|
module_names.add(full_name)
|
|
29
29
|
|
|
30
30
|
for path in paths:
|
|
31
|
-
full_name = get_full_name(path, action_prefixes)
|
|
31
|
+
full_name = get_full_name(path, action_prefixes, extensions=('.py',))
|
|
32
32
|
|
|
33
33
|
if full_name and full_name not in module_names:
|
|
34
34
|
print('%s: action plugin has no matching module to provide documentation' % path)
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
def get_full_name(path, prefixes):
|
|
37
|
+
def get_full_name(path: str, prefixes: dict[str, bool], extensions: tuple[str] | None = None) -> str | None:
|
|
38
38
|
"""Return the full name of the plugin at the given path by matching against the given path prefixes, or None if no match is found."""
|
|
39
39
|
for prefix, flat in prefixes.items():
|
|
40
40
|
if path.startswith(prefix):
|
|
@@ -45,13 +45,16 @@ def get_full_name(path, prefixes):
|
|
|
45
45
|
else:
|
|
46
46
|
full_name = relative_path
|
|
47
47
|
|
|
48
|
-
full_name = os.path.splitext(full_name)
|
|
48
|
+
full_name, file_ext = os.path.splitext(full_name)
|
|
49
49
|
|
|
50
50
|
name = os.path.basename(full_name)
|
|
51
51
|
|
|
52
52
|
if name == '__init__':
|
|
53
53
|
return None
|
|
54
54
|
|
|
55
|
+
if extensions and file_ext not in extensions:
|
|
56
|
+
return None
|
|
57
|
+
|
|
55
58
|
if name.startswith('_'):
|
|
56
59
|
name = name[1:]
|
|
57
60
|
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
disable=
|
|
4
4
|
consider-using-f-string, # Python 2.x support still required
|
|
5
5
|
cyclic-import, # consistent results require running with --jobs 1 and testing all files
|
|
6
|
+
deprecated-argument, # results vary by Python version
|
|
7
|
+
deprecated-attribute, # results vary by Python version
|
|
8
|
+
deprecated-class, # results vary by Python version
|
|
9
|
+
deprecated-decorator, # results vary by Python version
|
|
6
10
|
deprecated-method, # results vary by Python version
|
|
7
11
|
deprecated-module, # results vary by Python version
|
|
8
12
|
duplicate-code, # consistent results require running with --jobs 1 and testing all files
|
|
@@ -20,6 +24,7 @@ disable=
|
|
|
20
24
|
too-many-nested-blocks,
|
|
21
25
|
too-many-return-statements,
|
|
22
26
|
too-many-statements,
|
|
27
|
+
too-many-positional-arguments,
|
|
23
28
|
use-dict-literal, # ignoring as a common style issue
|
|
24
29
|
useless-return, # complains about returning None when the return type is optional
|
|
25
30
|
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
disable=
|
|
4
4
|
consider-using-f-string, # many occurrences
|
|
5
5
|
cyclic-import, # consistent results require running with --jobs 1 and testing all files
|
|
6
|
+
deprecated-argument, # results vary by Python version
|
|
7
|
+
deprecated-attribute, # results vary by Python version
|
|
8
|
+
deprecated-class, # results vary by Python version
|
|
9
|
+
deprecated-decorator, # results vary by Python version
|
|
6
10
|
deprecated-method, # results vary by Python version
|
|
7
11
|
deprecated-module, # results vary by Python version
|
|
8
12
|
duplicate-code, # consistent results require running with --jobs 1 and testing all files
|
|
@@ -18,6 +22,7 @@ disable=
|
|
|
18
22
|
too-many-nested-blocks,
|
|
19
23
|
too-many-return-statements,
|
|
20
24
|
too-many-statements,
|
|
25
|
+
too-many-positional-arguments,
|
|
21
26
|
use-dict-literal, # ignoring as a common style issue
|
|
22
27
|
unspecified-encoding, # always run with UTF-8 encoding enforced
|
|
23
28
|
useless-return, # complains about returning None when the return type is optional
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
disable=
|
|
4
4
|
consider-using-f-string, # many occurrences
|
|
5
5
|
cyclic-import, # consistent results require running with --jobs 1 and testing all files
|
|
6
|
+
deprecated-argument, # results vary by Python version
|
|
7
|
+
deprecated-attribute, # results vary by Python version
|
|
8
|
+
deprecated-class, # results vary by Python version
|
|
9
|
+
deprecated-decorator, # results vary by Python version
|
|
6
10
|
deprecated-method, # results vary by Python version
|
|
7
11
|
deprecated-module, # results vary by Python version
|
|
8
12
|
duplicate-code, # consistent results require running with --jobs 1 and testing all files
|
|
@@ -17,6 +21,7 @@ disable=
|
|
|
17
21
|
too-many-nested-blocks,
|
|
18
22
|
too-many-return-statements,
|
|
19
23
|
too-many-statements,
|
|
24
|
+
too-many-positional-arguments,
|
|
20
25
|
use-dict-literal, # ignoring as a common style issue
|
|
21
26
|
unspecified-encoding, # always run with UTF-8 encoding enforced
|
|
22
27
|
useless-return, # complains about returning None when the return type is optional
|
|
@@ -30,7 +30,11 @@ disable=
|
|
|
30
30
|
consider-using-max-builtin,
|
|
31
31
|
consider-using-min-builtin,
|
|
32
32
|
cyclic-import, # consistent results require running with --jobs 1 and testing all files
|
|
33
|
+
deprecated-argument, # results vary by Python version
|
|
34
|
+
deprecated-attribute, # results vary by Python version
|
|
35
|
+
deprecated-class, # results vary by Python version
|
|
33
36
|
deprecated-comment, # custom plugin only used by ansible-core, not collections
|
|
37
|
+
deprecated-decorator, # results vary by Python version
|
|
34
38
|
deprecated-method, # results vary by Python version
|
|
35
39
|
deprecated-module, # results vary by Python version
|
|
36
40
|
duplicate-code, # consistent results require running with --jobs 1 and testing all files
|
|
@@ -69,6 +73,7 @@ disable=
|
|
|
69
73
|
pointless-statement,
|
|
70
74
|
pointless-string-statement,
|
|
71
75
|
possibly-unused-variable,
|
|
76
|
+
possibly-used-before-assignment,
|
|
72
77
|
protected-access,
|
|
73
78
|
raise-missing-from, # Python 2.x does not support raise from
|
|
74
79
|
redefined-argument-from-local,
|
|
@@ -97,6 +102,7 @@ disable=
|
|
|
97
102
|
too-many-public-methods,
|
|
98
103
|
too-many-return-statements,
|
|
99
104
|
too-many-statements,
|
|
105
|
+
too-many-positional-arguments,
|
|
100
106
|
try-except-raise,
|
|
101
107
|
unbalanced-tuple-unpacking,
|
|
102
108
|
undefined-loop-variable,
|
|
@@ -28,6 +28,10 @@ disable=
|
|
|
28
28
|
consider-using-max-builtin,
|
|
29
29
|
consider-using-min-builtin,
|
|
30
30
|
cyclic-import, # consistent results require running with --jobs 1 and testing all files
|
|
31
|
+
deprecated-argument, # results vary by Python version
|
|
32
|
+
deprecated-attribute, # results vary by Python version
|
|
33
|
+
deprecated-class, # results vary by Python version
|
|
34
|
+
deprecated-decorator, # results vary by Python version
|
|
31
35
|
deprecated-method, # results vary by Python version
|
|
32
36
|
deprecated-module, # results vary by Python version
|
|
33
37
|
duplicate-code, # consistent results require running with --jobs 1 and testing all files
|
|
@@ -63,6 +67,7 @@ disable=
|
|
|
63
67
|
not-an-iterable,
|
|
64
68
|
not-callable,
|
|
65
69
|
possibly-unused-variable,
|
|
70
|
+
possibly-used-before-assignment,
|
|
66
71
|
protected-access,
|
|
67
72
|
raise-missing-from, # Python 2.x does not support raise from
|
|
68
73
|
redefined-argument-from-local,
|
|
@@ -90,6 +95,7 @@ disable=
|
|
|
90
95
|
too-many-public-methods,
|
|
91
96
|
too-many-return-statements,
|
|
92
97
|
too-many-statements,
|
|
98
|
+
too-many-positional-arguments,
|
|
93
99
|
try-except-raise,
|
|
94
100
|
unbalanced-tuple-unpacking,
|
|
95
101
|
undefined-loop-variable,
|
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
import datetime
|
|
8
|
-
import functools
|
|
9
|
-
import json
|
|
10
8
|
import re
|
|
11
9
|
import shlex
|
|
12
10
|
import typing as t
|
|
@@ -326,15 +324,6 @@ class AnsibleDeprecatedCommentChecker(BaseTokenChecker):
|
|
|
326
324
|
{'minversion': (2, 6)}),
|
|
327
325
|
}
|
|
328
326
|
|
|
329
|
-
options = (
|
|
330
|
-
('min-python-version-db', {
|
|
331
|
-
'default': None,
|
|
332
|
-
'type': 'string',
|
|
333
|
-
'metavar': '<path>',
|
|
334
|
-
'help': 'The path to the DB mapping paths to minimum Python versions.',
|
|
335
|
-
}),
|
|
336
|
-
)
|
|
337
|
-
|
|
338
327
|
def process_tokens(self, tokens: list[TokenInfo]) -> None:
|
|
339
328
|
for token in tokens:
|
|
340
329
|
if token.type == COMMENT:
|
|
@@ -365,15 +354,8 @@ class AnsibleDeprecatedCommentChecker(BaseTokenChecker):
|
|
|
365
354
|
)
|
|
366
355
|
return data
|
|
367
356
|
|
|
368
|
-
@functools.cached_property
|
|
369
|
-
def _min_python_version_db(self) -> dict[str, str]:
|
|
370
|
-
"""A dictionary of absolute file paths and their minimum required Python version."""
|
|
371
|
-
with open(self.linter.config.min_python_version_db) as db_file:
|
|
372
|
-
return json.load(db_file)
|
|
373
|
-
|
|
374
357
|
def _process_python_version(self, token: TokenInfo, data: dict[str, str]) -> None:
|
|
375
|
-
|
|
376
|
-
check_version = self._min_python_version_db[current_file]
|
|
358
|
+
check_version = '.'.join(map(str, self.linter.config.py_version))
|
|
377
359
|
|
|
378
360
|
try:
|
|
379
361
|
if LooseVersion(data['python_version']) < LooseVersion(check_version):
|