ansible-core 2.19.4rc1__py3-none-any.whl → 2.20.0__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/_internal/__init__.py +1 -4
- ansible/_internal/_ansiballz/_builder.py +1 -3
- ansible/_internal/_collection_proxy.py +7 -9
- ansible/_internal/_json/__init__.py +3 -4
- ansible/_internal/_templating/_engine.py +1 -1
- ansible/_internal/_templating/_jinja_plugins.py +1 -2
- ansible/_internal/_wrapt.py +105 -301
- ansible/cli/__init__.py +11 -10
- ansible/cli/adhoc.py +1 -2
- ansible/cli/arguments/option_helpers.py +1 -1
- ansible/cli/config.py +5 -6
- ansible/cli/doc.py +67 -67
- ansible/cli/galaxy.py +15 -24
- ansible/cli/inventory.py +0 -1
- ansible/cli/playbook.py +0 -1
- ansible/cli/pull.py +0 -1
- ansible/cli/scripts/ansible_connection_cli_stub.py +1 -1
- ansible/config/base.yml +1 -25
- ansible/config/manager.py +0 -2
- ansible/executor/play_iterator.py +42 -20
- ansible/executor/playbook_executor.py +0 -9
- ansible/executor/task_executor.py +26 -18
- ansible/executor/task_queue_manager.py +1 -3
- ansible/galaxy/api.py +33 -80
- ansible/galaxy/collection/__init__.py +11 -21
- ansible/galaxy/dependency_resolution/__init__.py +10 -9
- ansible/galaxy/dependency_resolution/dataclasses.py +86 -70
- ansible/galaxy/dependency_resolution/providers.py +54 -134
- ansible/galaxy/dependency_resolution/versioning.py +2 -4
- ansible/galaxy/role.py +1 -33
- ansible/inventory/manager.py +2 -3
- ansible/keyword_desc.yml +0 -3
- ansible/module_utils/_internal/_datatag/__init__.py +2 -10
- ansible/module_utils/_internal/_no_six.py +86 -0
- ansible/module_utils/_text.py +28 -8
- ansible/module_utils/ansible_release.py +2 -2
- ansible/module_utils/basic.py +26 -23
- ansible/module_utils/common/_collections_compat.py +11 -2
- ansible/module_utils/common/collections.py +8 -3
- ansible/module_utils/common/dict_transformations.py +1 -2
- ansible/module_utils/common/network.py +4 -2
- ansible/module_utils/common/parameters.py +32 -41
- ansible/module_utils/common/text/converters.py +109 -23
- ansible/module_utils/common/text/formatters.py +6 -2
- ansible/module_utils/common/validation.py +11 -9
- ansible/module_utils/connection.py +8 -3
- ansible/module_utils/facts/hardware/linux.py +23 -7
- ansible/module_utils/facts/hardware/netbsd.py +1 -1
- ansible/module_utils/facts/hardware/sunos.py +2 -1
- ansible/module_utils/facts/packages.py +6 -2
- ansible/module_utils/facts/system/distribution.py +2 -1
- ansible/module_utils/facts/system/env.py +6 -3
- ansible/module_utils/facts/system/local.py +3 -1
- ansible/module_utils/parsing/convert_bool.py +6 -2
- ansible/module_utils/service.py +2 -3
- ansible/module_utils/six/__init__.py +11 -6
- ansible/module_utils/yumdnf.py +0 -5
- ansible/modules/apt.py +18 -13
- ansible/modules/apt_repository.py +1 -1
- ansible/modules/assemble.py +5 -9
- ansible/modules/blockinfile.py +39 -23
- ansible/modules/cron.py +26 -35
- ansible/modules/deb822_repository.py +83 -12
- ansible/modules/dnf.py +3 -7
- ansible/modules/dnf5.py +4 -6
- ansible/modules/expect.py +0 -3
- ansible/modules/find.py +1 -2
- ansible/modules/get_url.py +1 -1
- ansible/modules/git.py +4 -5
- ansible/modules/include_vars.py +1 -1
- ansible/modules/known_hosts.py +7 -1
- ansible/modules/lineinfile.py +71 -63
- ansible/modules/package_facts.py +1 -1
- ansible/modules/pip.py +8 -2
- ansible/modules/replace.py +6 -6
- ansible/modules/service.py +3 -4
- ansible/modules/stat.py +20 -0
- ansible/modules/uri.py +9 -10
- ansible/modules/user.py +1 -2
- ansible/modules/wait_for.py +2 -2
- ansible/modules/wait_for_connection.py +2 -1
- ansible/modules/yum_repository.py +1 -16
- ansible/parsing/dataloader.py +24 -31
- ansible/parsing/vault/__init__.py +1 -2
- ansible/playbook/base.py +8 -56
- ansible/playbook/block.py +0 -60
- ansible/playbook/collectionsearch.py +1 -2
- ansible/playbook/handler.py +1 -7
- ansible/playbook/helpers.py +0 -7
- ansible/playbook/included_file.py +1 -1
- ansible/playbook/play.py +102 -36
- ansible/playbook/play_context.py +4 -0
- ansible/playbook/role/__init__.py +10 -65
- ansible/playbook/role/definition.py +3 -4
- ansible/playbook/role/include.py +2 -3
- ansible/playbook/role/metadata.py +1 -12
- ansible/playbook/role/requirement.py +1 -2
- ansible/playbook/role_include.py +1 -2
- ansible/playbook/taggable.py +16 -5
- ansible/playbook/task.py +11 -50
- ansible/plugins/action/__init__.py +20 -19
- ansible/plugins/action/add_host.py +1 -2
- ansible/plugins/action/fetch.py +3 -5
- ansible/plugins/action/group_by.py +1 -2
- ansible/plugins/action/include_vars.py +20 -22
- ansible/plugins/action/script.py +1 -3
- ansible/plugins/action/template.py +1 -2
- ansible/plugins/action/uri.py +4 -2
- ansible/plugins/cache/__init__.py +1 -0
- ansible/plugins/callback/__init__.py +13 -6
- ansible/plugins/connection/__init__.py +3 -7
- ansible/plugins/connection/local.py +2 -3
- ansible/plugins/connection/psrp.py +0 -2
- ansible/plugins/connection/ssh.py +2 -7
- ansible/plugins/connection/winrm.py +0 -2
- ansible/plugins/doc_fragments/result_format_callback.py +15 -0
- ansible/plugins/filter/core.py +4 -5
- ansible/plugins/filter/encryption.py +3 -27
- ansible/plugins/filter/mathstuff.py +1 -2
- ansible/plugins/filter/to_nice_yaml.yml +31 -3
- ansible/plugins/filter/to_yaml.yml +29 -12
- ansible/plugins/inventory/__init__.py +1 -2
- ansible/plugins/inventory/toml.py +3 -6
- ansible/plugins/inventory/yaml.py +1 -2
- ansible/plugins/loader.py +3 -4
- ansible/plugins/lookup/password.py +1 -2
- ansible/plugins/lookup/subelements.py +2 -3
- ansible/plugins/lookup/url.py +1 -1
- ansible/plugins/lookup/varnames.py +1 -2
- ansible/plugins/shell/__init__.py +9 -4
- ansible/plugins/shell/powershell.py +8 -24
- ansible/plugins/strategy/__init__.py +5 -2
- ansible/plugins/test/core.py +4 -1
- ansible/plugins/test/falsy.yml +1 -1
- ansible/plugins/test/regex.yml +18 -6
- ansible/plugins/test/truthy.yml +1 -1
- ansible/release.py +2 -2
- ansible/template/__init__.py +3 -7
- ansible/utils/collection_loader/_collection_config.py +5 -0
- ansible/utils/collection_loader/_collection_finder.py +11 -14
- ansible/utils/context_objects.py +7 -4
- ansible/utils/display.py +7 -6
- ansible/utils/encrypt.py +0 -5
- ansible/utils/helpers.py +6 -2
- ansible/utils/jsonrpc.py +7 -3
- ansible/utils/plugin_docs.py +49 -38
- ansible/utils/ssh_functions.py +0 -19
- ansible/utils/unsafe_proxy.py +7 -7
- ansible/vars/clean.py +2 -3
- ansible/vars/manager.py +28 -22
- ansible/vars/plugins.py +1 -31
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/METADATA +4 -4
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/RECORD +213 -214
- ansible_test/_data/completion/docker.txt +7 -7
- ansible_test/_data/completion/network.txt +0 -1
- ansible_test/_data/completion/remote.txt +4 -4
- ansible_test/_data/requirements/ansible-test.txt +1 -1
- ansible_test/_data/requirements/ansible.txt +1 -1
- ansible_test/_data/requirements/sanity.ansible-doc.txt +2 -2
- ansible_test/_data/requirements/sanity.changelog.txt +2 -2
- 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 -6
- ansible_test/_data/requirements/sanity.runtime-metadata.txt +1 -1
- ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
- ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
- ansible_test/_internal/cache.py +2 -5
- ansible_test/_internal/cli/compat.py +1 -1
- ansible_test/_internal/commands/coverage/combine.py +1 -3
- ansible_test/_internal/commands/integration/__init__.py +3 -7
- ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
- ansible_test/_internal/commands/integration/coverage.py +1 -3
- ansible_test/_internal/commands/integration/filters.py +5 -10
- ansible_test/_internal/commands/sanity/pylint.py +11 -0
- ansible_test/_internal/commands/sanity/validate_modules.py +1 -5
- ansible_test/_internal/commands/units/__init__.py +1 -13
- ansible_test/_internal/compat/packaging.py +2 -2
- ansible_test/_internal/compat/yaml.py +2 -2
- ansible_test/_internal/completion.py +2 -5
- ansible_test/_internal/config.py +2 -7
- ansible_test/_internal/coverage_util.py +1 -1
- ansible_test/_internal/delegation.py +2 -0
- ansible_test/_internal/docker_util.py +1 -1
- ansible_test/_internal/host_profiles.py +6 -11
- ansible_test/_internal/provider/__init__.py +2 -5
- ansible_test/_internal/provisioning.py +2 -5
- ansible_test/_internal/pypi_proxy.py +1 -1
- ansible_test/_internal/python_requirements.py +1 -1
- ansible_test/_internal/target.py +2 -6
- ansible_test/_internal/thread.py +1 -4
- ansible_test/_internal/util.py +9 -14
- ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +14 -19
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +48 -45
- ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +9 -7
- ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +51 -37
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +31 -18
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +1 -2
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +59 -71
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -2
- ansible_test/_util/target/cli/ansible_test_cli_stub.py +4 -2
- ansible_test/_util/target/common/constants.py +2 -2
- ansible_test/_util/target/setup/bootstrap.sh +0 -6
- ansible/utils/py3compat.py +0 -27
- ansible_test/_data/pytest/config/legacy.ini +0 -4
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/WHEEL +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/top_level.txt +0 -0
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
|
+
import collections.abc as _c
|
|
8
9
|
import functools
|
|
9
10
|
import typing as t
|
|
10
11
|
|
|
@@ -15,6 +16,8 @@ if t.TYPE_CHECKING:
|
|
|
15
16
|
from ansible.galaxy.collection.galaxy_api_proxy import MultiGalaxyAPIProxy
|
|
16
17
|
from ansible.galaxy.api import GalaxyAPI
|
|
17
18
|
|
|
19
|
+
from resolvelib.structs import RequirementInformation
|
|
20
|
+
|
|
18
21
|
from ansible.galaxy.collection.gpg import get_signature_from_source
|
|
19
22
|
from ansible.galaxy.dependency_resolution.dataclasses import (
|
|
20
23
|
Candidate,
|
|
@@ -24,7 +27,6 @@ from ansible.galaxy.dependency_resolution.versioning import (
|
|
|
24
27
|
is_pre_release,
|
|
25
28
|
meets_requirements,
|
|
26
29
|
)
|
|
27
|
-
from ansible.module_utils.six import string_types
|
|
28
30
|
from ansible.utils.version import SemanticVersion, LooseVersion
|
|
29
31
|
|
|
30
32
|
try:
|
|
@@ -38,24 +40,24 @@ except ImportError:
|
|
|
38
40
|
|
|
39
41
|
|
|
40
42
|
# TODO: add python requirements to ansible-test's ansible-core distribution info and remove the hardcoded lowerbound/upperbound fallback
|
|
41
|
-
RESOLVELIB_LOWERBOUND = SemanticVersion("0.
|
|
43
|
+
RESOLVELIB_LOWERBOUND = SemanticVersion("0.8.0")
|
|
42
44
|
RESOLVELIB_UPPERBOUND = SemanticVersion("2.0.0")
|
|
43
45
|
RESOLVELIB_VERSION = SemanticVersion.from_loose_version(LooseVersion(resolvelib_version))
|
|
44
46
|
|
|
45
47
|
|
|
46
|
-
class
|
|
48
|
+
class CollectionDependencyProvider(AbstractProvider):
|
|
47
49
|
"""Delegate providing a requirement interface for the resolver."""
|
|
48
50
|
|
|
49
51
|
def __init__(
|
|
50
|
-
self,
|
|
51
|
-
apis
|
|
52
|
-
concrete_artifacts_manager
|
|
53
|
-
preferred_candidates
|
|
54
|
-
with_deps=True,
|
|
55
|
-
with_pre_releases=False,
|
|
56
|
-
upgrade=False,
|
|
57
|
-
include_signatures=True,
|
|
58
|
-
)
|
|
52
|
+
self,
|
|
53
|
+
apis: MultiGalaxyAPIProxy,
|
|
54
|
+
concrete_artifacts_manager: ConcreteArtifactsManager,
|
|
55
|
+
preferred_candidates: _c.Iterable[Candidate] | None = None,
|
|
56
|
+
with_deps: bool = True,
|
|
57
|
+
with_pre_releases: bool = False,
|
|
58
|
+
upgrade: bool = False,
|
|
59
|
+
include_signatures: bool = True,
|
|
60
|
+
) -> None:
|
|
59
61
|
r"""Initialize helper attributes.
|
|
60
62
|
|
|
61
63
|
:param api: An instance of the multiple Galaxy APIs wrapper.
|
|
@@ -91,8 +93,10 @@ class CollectionDependencyProviderBase(AbstractProvider):
|
|
|
91
93
|
self._upgrade = upgrade
|
|
92
94
|
self._include_signatures = include_signatures
|
|
93
95
|
|
|
94
|
-
def identify(
|
|
95
|
-
|
|
96
|
+
def identify(
|
|
97
|
+
self,
|
|
98
|
+
requirement_or_candidate: Candidate | Requirement,
|
|
99
|
+
) -> str:
|
|
96
100
|
"""Given requirement or candidate, return an identifier for it.
|
|
97
101
|
|
|
98
102
|
This is used to identify a requirement or candidate, e.g.
|
|
@@ -103,8 +107,19 @@ class CollectionDependencyProviderBase(AbstractProvider):
|
|
|
103
107
|
"""
|
|
104
108
|
return requirement_or_candidate.canonical_package_id
|
|
105
109
|
|
|
106
|
-
def get_preference(
|
|
107
|
-
|
|
110
|
+
def get_preference(
|
|
111
|
+
self,
|
|
112
|
+
identifier: str,
|
|
113
|
+
resolutions: _c.Mapping[str, Candidate],
|
|
114
|
+
candidates: _c.Mapping[str, _c.Iterator[Candidate]],
|
|
115
|
+
information: _c.Mapping[
|
|
116
|
+
str,
|
|
117
|
+
_c.Iterator[RequirementInformation[Requirement, Candidate]],
|
|
118
|
+
],
|
|
119
|
+
backtrack_causes: _c.Sequence[
|
|
120
|
+
RequirementInformation[Requirement, Candidate],
|
|
121
|
+
],
|
|
122
|
+
) -> float | int:
|
|
108
123
|
"""Return sort key function return value for given requirement.
|
|
109
124
|
|
|
110
125
|
This result should be based on preference that is defined as
|
|
@@ -112,38 +127,6 @@ class CollectionDependencyProviderBase(AbstractProvider):
|
|
|
112
127
|
The lower the return value is, the more preferred this
|
|
113
128
|
group of arguments is.
|
|
114
129
|
|
|
115
|
-
resolvelib >=0.5.3, <0.7.0
|
|
116
|
-
|
|
117
|
-
:param resolution: Currently pinned candidate, or ``None``.
|
|
118
|
-
|
|
119
|
-
:param candidates: A list of possible candidates.
|
|
120
|
-
|
|
121
|
-
:param information: A list of requirement information.
|
|
122
|
-
|
|
123
|
-
Each ``information`` instance is a named tuple with two entries:
|
|
124
|
-
|
|
125
|
-
* ``requirement`` specifies a requirement contributing to
|
|
126
|
-
the current candidate list
|
|
127
|
-
|
|
128
|
-
* ``parent`` specifies the candidate that provides
|
|
129
|
-
(depended on) the requirement, or `None`
|
|
130
|
-
to indicate a root requirement.
|
|
131
|
-
|
|
132
|
-
resolvelib >=0.7.0, < 0.8.0
|
|
133
|
-
|
|
134
|
-
:param identifier: The value returned by ``identify()``.
|
|
135
|
-
|
|
136
|
-
:param resolutions: Mapping of identifier, candidate pairs.
|
|
137
|
-
|
|
138
|
-
:param candidates: Possible candidates for the identifier.
|
|
139
|
-
Mapping of identifier, list of candidate pairs.
|
|
140
|
-
|
|
141
|
-
:param information: Requirement information of each package.
|
|
142
|
-
Mapping of identifier, list of named tuple pairs.
|
|
143
|
-
The named tuples have the entries ``requirement`` and ``parent``.
|
|
144
|
-
|
|
145
|
-
resolvelib >=0.8.0, <= 1.0.1
|
|
146
|
-
|
|
147
130
|
:param identifier: The value returned by ``identify()``.
|
|
148
131
|
|
|
149
132
|
:param resolutions: Mapping of identifier, candidate pairs.
|
|
@@ -179,10 +162,6 @@ class CollectionDependencyProviderBase(AbstractProvider):
|
|
|
179
162
|
the value is, the more preferred this requirement is (i.e. the
|
|
180
163
|
sorting function is called with ``reverse=False``).
|
|
181
164
|
"""
|
|
182
|
-
raise NotImplementedError
|
|
183
|
-
|
|
184
|
-
def _get_preference(self, candidates):
|
|
185
|
-
# type: (list[Candidate]) -> t.Union[float, int]
|
|
186
165
|
if any(
|
|
187
166
|
candidate in self._preferred_candidates
|
|
188
167
|
for candidate in candidates
|
|
@@ -192,8 +171,12 @@ class CollectionDependencyProviderBase(AbstractProvider):
|
|
|
192
171
|
return float('-inf')
|
|
193
172
|
return len(candidates)
|
|
194
173
|
|
|
195
|
-
def find_matches(
|
|
196
|
-
|
|
174
|
+
def find_matches(
|
|
175
|
+
self,
|
|
176
|
+
identifier: str,
|
|
177
|
+
requirements: _c.Mapping[str, _c.Iterator[Requirement]],
|
|
178
|
+
incompatibilities: _c.Mapping[str, _c.Iterator[Candidate]],
|
|
179
|
+
) -> list[Candidate]:
|
|
197
180
|
r"""Find all possible candidates satisfying given requirements.
|
|
198
181
|
|
|
199
182
|
This tries to get candidates based on the requirements' types.
|
|
@@ -204,32 +187,13 @@ class CollectionDependencyProviderBase(AbstractProvider):
|
|
|
204
187
|
For a "named" requirement, Galaxy-compatible APIs are consulted
|
|
205
188
|
to find concrete candidates for this requirement. If there's a
|
|
206
189
|
pre-installed candidate, it's prepended in front of others.
|
|
207
|
-
|
|
208
|
-
resolvelib >=0.5.3, <0.6.0
|
|
209
|
-
|
|
210
|
-
:param requirements: A collection of requirements which all of \
|
|
211
|
-
the returned candidates must match. \
|
|
212
|
-
All requirements are guaranteed to have \
|
|
213
|
-
the same identifier. \
|
|
214
|
-
The collection is never empty.
|
|
215
|
-
|
|
216
|
-
resolvelib >=0.6.0
|
|
217
|
-
|
|
218
|
-
:param identifier: The value returned by ``identify()``.
|
|
219
|
-
|
|
220
|
-
:param requirements: The requirements all returned candidates must satisfy.
|
|
221
|
-
Mapping of identifier, iterator of requirement pairs.
|
|
222
|
-
|
|
223
|
-
:param incompatibilities: Incompatible versions that must be excluded
|
|
224
|
-
from the returned list.
|
|
225
|
-
|
|
226
|
-
:returns: An iterable that orders candidates by preference, \
|
|
227
|
-
e.g. the most preferred candidate comes first.
|
|
228
190
|
"""
|
|
229
|
-
|
|
191
|
+
return [
|
|
192
|
+
match for match in self._find_matches(list(requirements[identifier]))
|
|
193
|
+
if not any(match.ver == incompat.ver for incompat in incompatibilities[identifier])
|
|
194
|
+
]
|
|
230
195
|
|
|
231
|
-
def _find_matches(self, requirements):
|
|
232
|
-
# type: (list[Requirement]) -> list[Candidate]
|
|
196
|
+
def _find_matches(self, requirements: list[Requirement]) -> list[Candidate]:
|
|
233
197
|
# FIXME: The first requirement may be a Git repo followed by
|
|
234
198
|
# FIXME: its cloned tmp dir. Using only the first one creates
|
|
235
199
|
# FIXME: loops that prevent any further dependency exploration.
|
|
@@ -250,7 +214,10 @@ class CollectionDependencyProviderBase(AbstractProvider):
|
|
|
250
214
|
all(self.is_satisfied_by(requirement, candidate) for requirement in requirements)
|
|
251
215
|
}
|
|
252
216
|
try:
|
|
253
|
-
coll_versions
|
|
217
|
+
coll_versions: _c.Iterable[tuple[str, GalaxyAPI]] = (
|
|
218
|
+
[] if preinstalled_candidates
|
|
219
|
+
else self._api_proxy.get_collection_versions(first_req)
|
|
220
|
+
)
|
|
254
221
|
except TypeError as exc:
|
|
255
222
|
if first_req.is_concrete_artifact:
|
|
256
223
|
# Non hashable versions will cause a TypeError
|
|
@@ -278,7 +245,7 @@ class CollectionDependencyProviderBase(AbstractProvider):
|
|
|
278
245
|
# NOTE: Another known mistake is setting a minor part of the SemVer notation
|
|
279
246
|
# NOTE: skipping the "patch" bit like "1.0" which is assumed non-compliant even
|
|
280
247
|
# NOTE: after the conversion to string.
|
|
281
|
-
if not isinstance(version,
|
|
248
|
+
if not isinstance(version, str):
|
|
282
249
|
raise ValueError(version_err)
|
|
283
250
|
elif version != '*':
|
|
284
251
|
try:
|
|
@@ -293,7 +260,7 @@ class CollectionDependencyProviderBase(AbstractProvider):
|
|
|
293
260
|
|
|
294
261
|
latest_matches = []
|
|
295
262
|
signatures = []
|
|
296
|
-
extra_signature_sources
|
|
263
|
+
extra_signature_sources: list[str] = []
|
|
297
264
|
|
|
298
265
|
discarding_pre_releases_acceptable = any(
|
|
299
266
|
not is_pre_release(candidate_version)
|
|
@@ -398,8 +365,11 @@ class CollectionDependencyProviderBase(AbstractProvider):
|
|
|
398
365
|
|
|
399
366
|
return list(preinstalled_candidates) + latest_matches
|
|
400
367
|
|
|
401
|
-
def is_satisfied_by(
|
|
402
|
-
|
|
368
|
+
def is_satisfied_by(
|
|
369
|
+
self,
|
|
370
|
+
requirement: Requirement,
|
|
371
|
+
candidate: Candidate,
|
|
372
|
+
) -> bool:
|
|
403
373
|
r"""Whether the given requirement is satisfiable by a candidate.
|
|
404
374
|
|
|
405
375
|
:param requirement: A requirement that produced the `candidate`.
|
|
@@ -425,8 +395,7 @@ class CollectionDependencyProviderBase(AbstractProvider):
|
|
|
425
395
|
requirements=requirement.ver,
|
|
426
396
|
)
|
|
427
397
|
|
|
428
|
-
def get_dependencies(self, candidate):
|
|
429
|
-
# type: (Candidate) -> list[Candidate]
|
|
398
|
+
def get_dependencies(self, candidate: Candidate) -> list[Requirement]:
|
|
430
399
|
r"""Get direct dependencies of a candidate.
|
|
431
400
|
|
|
432
401
|
:returns: A collection of requirements that `candidate` \
|
|
@@ -457,52 +426,3 @@ class CollectionDependencyProviderBase(AbstractProvider):
|
|
|
457
426
|
self._make_req_from_dict({'name': dep_name, 'version': dep_req})
|
|
458
427
|
for dep_name, dep_req in req_map.items()
|
|
459
428
|
]
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
# Classes to handle resolvelib API changes between minor versions for 0.X
|
|
463
|
-
class CollectionDependencyProvider050(CollectionDependencyProviderBase):
|
|
464
|
-
def find_matches(self, requirements): # type: ignore[override]
|
|
465
|
-
# type: (list[Requirement]) -> list[Candidate]
|
|
466
|
-
return self._find_matches(requirements)
|
|
467
|
-
|
|
468
|
-
def get_preference(self, resolution, candidates, information): # type: ignore[override]
|
|
469
|
-
# type: (t.Optional[Candidate], list[Candidate], list[t.NamedTuple]) -> t.Union[float, int]
|
|
470
|
-
return self._get_preference(candidates)
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
class CollectionDependencyProvider060(CollectionDependencyProviderBase):
|
|
474
|
-
def find_matches(self, identifier, requirements, incompatibilities): # type: ignore[override]
|
|
475
|
-
# type: (str, t.Mapping[str, t.Iterator[Requirement]], t.Mapping[str, t.Iterator[Requirement]]) -> list[Candidate]
|
|
476
|
-
return [
|
|
477
|
-
match for match in self._find_matches(list(requirements[identifier]))
|
|
478
|
-
if not any(match.ver == incompat.ver for incompat in incompatibilities[identifier])
|
|
479
|
-
]
|
|
480
|
-
|
|
481
|
-
def get_preference(self, resolution, candidates, information): # type: ignore[override]
|
|
482
|
-
# type: (t.Optional[Candidate], list[Candidate], list[t.NamedTuple]) -> t.Union[float, int]
|
|
483
|
-
return self._get_preference(candidates)
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
class CollectionDependencyProvider070(CollectionDependencyProvider060):
|
|
487
|
-
def get_preference(self, identifier, resolutions, candidates, information): # type: ignore[override]
|
|
488
|
-
# type: (str, t.Mapping[str, Candidate], t.Mapping[str, t.Iterator[Candidate]], t.Iterator[t.NamedTuple]) -> t.Union[float, int]
|
|
489
|
-
return self._get_preference(list(candidates[identifier]))
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
class CollectionDependencyProvider080(CollectionDependencyProvider060):
|
|
493
|
-
def get_preference(self, identifier, resolutions, candidates, information, backtrack_causes): # type: ignore[override]
|
|
494
|
-
# type: (str, t.Mapping[str, Candidate], t.Mapping[str, t.Iterator[Candidate]], t.Iterator[t.NamedTuple], t.Sequence) -> t.Union[float, int]
|
|
495
|
-
return self._get_preference(list(candidates[identifier]))
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
def _get_provider(): # type () -> CollectionDependencyProviderBase
|
|
499
|
-
if RESOLVELIB_VERSION >= SemanticVersion("0.8.0"):
|
|
500
|
-
return CollectionDependencyProvider080
|
|
501
|
-
if RESOLVELIB_VERSION >= SemanticVersion("0.7.0"):
|
|
502
|
-
return CollectionDependencyProvider070
|
|
503
|
-
if RESOLVELIB_VERSION >= SemanticVersion("0.6.0"):
|
|
504
|
-
return CollectionDependencyProvider060
|
|
505
|
-
return CollectionDependencyProvider050
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
CollectionDependencyProvider = _get_provider()
|
|
@@ -11,8 +11,7 @@ from ansible.module_utils.compat.version import LooseVersion
|
|
|
11
11
|
from ansible.utils.version import SemanticVersion
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
def is_pre_release(version):
|
|
15
|
-
# type: (str) -> bool
|
|
14
|
+
def is_pre_release(version: str) -> bool:
|
|
16
15
|
"""Figure out if a given version is a pre-release."""
|
|
17
16
|
try:
|
|
18
17
|
return SemanticVersion(version).is_prerelease
|
|
@@ -20,8 +19,7 @@ def is_pre_release(version):
|
|
|
20
19
|
return False
|
|
21
20
|
|
|
22
21
|
|
|
23
|
-
def meets_requirements(version, requirements):
|
|
24
|
-
# type: (str, str) -> bool
|
|
22
|
+
def meets_requirements(version: str, requirements: str) -> bool:
|
|
25
23
|
"""Verify if a given version satisfies all the requirements.
|
|
26
24
|
|
|
27
25
|
Supported version identifiers are:
|
ansible/galaxy/role.py
CHANGED
|
@@ -23,7 +23,6 @@ from __future__ import annotations
|
|
|
23
23
|
|
|
24
24
|
import errno
|
|
25
25
|
import datetime
|
|
26
|
-
import functools
|
|
27
26
|
import os
|
|
28
27
|
import tarfile
|
|
29
28
|
import tempfile
|
|
@@ -46,32 +45,6 @@ from ansible.utils.path import is_subpath, unfrackpath
|
|
|
46
45
|
display = Display()
|
|
47
46
|
|
|
48
47
|
|
|
49
|
-
@functools.cache
|
|
50
|
-
def _check_working_data_filter() -> bool:
|
|
51
|
-
"""
|
|
52
|
-
Check if tarfile.data_filter implementation is working
|
|
53
|
-
for the current Python version or not
|
|
54
|
-
"""
|
|
55
|
-
|
|
56
|
-
# Implemented the following code to circumvent broken implementation of data_filter
|
|
57
|
-
# in tarfile. See for more information - https://github.com/python/cpython/issues/107845
|
|
58
|
-
# deprecated: description='probing broken data filter implementation' python_version='3.11'
|
|
59
|
-
ret = False
|
|
60
|
-
if hasattr(tarfile, 'data_filter'):
|
|
61
|
-
# We explicitly check if tarfile.data_filter is broken or not
|
|
62
|
-
ti = tarfile.TarInfo('docs/README.md')
|
|
63
|
-
ti.type = tarfile.SYMTYPE
|
|
64
|
-
ti.linkname = '../README.md'
|
|
65
|
-
|
|
66
|
-
try:
|
|
67
|
-
tarfile.data_filter(ti, '/foo')
|
|
68
|
-
except tarfile.LinkOutsideDestinationError:
|
|
69
|
-
pass
|
|
70
|
-
else:
|
|
71
|
-
ret = True
|
|
72
|
-
return ret
|
|
73
|
-
|
|
74
|
-
|
|
75
48
|
class GalaxyRole(object):
|
|
76
49
|
|
|
77
50
|
SUPPORTED_SCMS = set(['git', 'hg'])
|
|
@@ -418,12 +391,7 @@ class GalaxyRole(object):
|
|
|
418
391
|
relative_path = os.path.join(*full_path.replace(relative_path_dir, "", 1).split(os.sep))
|
|
419
392
|
setattr(member, attr, relative_path)
|
|
420
393
|
|
|
421
|
-
|
|
422
|
-
# deprecated: description='extract fallback without filter' python_version='3.11'
|
|
423
|
-
role_tar_file.extract(member, to_native(self.path), filter='data') # type: ignore[call-arg]
|
|
424
|
-
else:
|
|
425
|
-
# Remove along with manual path filter once Python 3.12 is minimum supported version
|
|
426
|
-
role_tar_file.extract(member, to_native(self.path))
|
|
394
|
+
role_tar_file.extract(member, to_native(self.path), filter='data')
|
|
427
395
|
|
|
428
396
|
# write out the install info file for later use
|
|
429
397
|
self._write_galaxy_install_info()
|
ansible/inventory/manager.py
CHANGED
|
@@ -33,7 +33,6 @@ from ansible._internal import _json, _wrapt
|
|
|
33
33
|
from ansible._internal._json import EncryptedStringBehavior
|
|
34
34
|
from ansible.errors import AnsibleError, AnsibleOptionsError
|
|
35
35
|
from ansible.inventory.data import InventoryData
|
|
36
|
-
from ansible.module_utils.six import string_types
|
|
37
36
|
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
|
38
37
|
from ansible.parsing.utils.addresses import parse_address
|
|
39
38
|
from ansible.plugins.loader import inventory_loader
|
|
@@ -112,7 +111,7 @@ def split_host_pattern(pattern):
|
|
|
112
111
|
results = (split_host_pattern(p) for p in pattern)
|
|
113
112
|
# flatten the results
|
|
114
113
|
return list(itertools.chain.from_iterable(results))
|
|
115
|
-
elif not isinstance(pattern,
|
|
114
|
+
elif not isinstance(pattern, str):
|
|
116
115
|
pattern = to_text(pattern, errors='surrogate_or_strict')
|
|
117
116
|
|
|
118
117
|
# If it's got commas in it, we'll treat it as a straightforward
|
|
@@ -162,7 +161,7 @@ class InventoryManager(object):
|
|
|
162
161
|
# the inventory dirs, files, script paths or lists of hosts
|
|
163
162
|
if sources is None:
|
|
164
163
|
self._sources = []
|
|
165
|
-
elif isinstance(sources,
|
|
164
|
+
elif isinstance(sources, str):
|
|
166
165
|
self._sources = [sources]
|
|
167
166
|
else:
|
|
168
167
|
self._sources = sources
|
ansible/keyword_desc.yml
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
accelerate: "*DEPRECATED*, set to True to use accelerate connection plugin."
|
|
2
|
-
accelerate_ipv6: "*DEPRECATED*, set to True to force accelerate plugin to use ipv6 for its connection."
|
|
3
|
-
accelerate_port: "*DEPRECATED*, set to override default port use for accelerate connection."
|
|
4
1
|
action: "The 'action' to execute for a task, it normally translates into a C(module) or action plugin."
|
|
5
2
|
args: "A secondary way to add arguments into a task. Takes a dictionary in which keys map to options and values."
|
|
6
3
|
always: List of tasks, in a block, that execute no matter if there is an error in the block or not.
|
|
@@ -500,17 +500,9 @@ class AnsibleDatatagBase(AnsibleSerializableDataclass, metaclass=abc.ABCMeta):
|
|
|
500
500
|
_known_tag_type_map: t.Dict[str, t.Type[AnsibleDatatagBase]] = {}
|
|
501
501
|
_known_tag_types: t.Set[t.Type[AnsibleDatatagBase]] = set()
|
|
502
502
|
|
|
503
|
-
if sys.version_info >= (3, 9):
|
|
504
|
-
# Include the key and value types in the type hints on Python 3.9 and later.
|
|
505
|
-
# Earlier versions do not support subscriptable dict.
|
|
506
|
-
# deprecated: description='always use subscriptable dict' python_version='3.8'
|
|
507
|
-
class _AnsibleTagsMapping(dict[type[_TAnsibleDatatagBase], _TAnsibleDatatagBase]):
|
|
508
|
-
__slots__ = _NO_INSTANCE_STORAGE
|
|
509
503
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
class _AnsibleTagsMapping(dict):
|
|
513
|
-
__slots__ = _NO_INSTANCE_STORAGE
|
|
504
|
+
class _AnsibleTagsMapping(dict[type[_TAnsibleDatatagBase], _TAnsibleDatatagBase]):
|
|
505
|
+
__slots__ = _NO_INSTANCE_STORAGE
|
|
514
506
|
|
|
515
507
|
|
|
516
508
|
class _EmptyROInternalTagsMapping(dict):
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
import types
|
|
5
|
+
|
|
6
|
+
from ansible.module_utils.common import warnings
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# INLINED FROM THE SIX LIBRARY, see lib/ansible/module_utils/six/__init__.py
|
|
10
|
+
# Copyright (c) 2010-2024 Benjamin Peterson
|
|
11
|
+
def with_metaclass(meta, *bases):
|
|
12
|
+
"""Create a base class with a metaclass."""
|
|
13
|
+
|
|
14
|
+
# This requires a bit of explanation: the basic idea is to make a dummy
|
|
15
|
+
# metaclass for one level of class instantiation that replaces itself with
|
|
16
|
+
# the actual metaclass.
|
|
17
|
+
class metaclass(type):
|
|
18
|
+
|
|
19
|
+
def __new__(cls, name, this_bases, d):
|
|
20
|
+
if sys.version_info[:2] >= (3, 7):
|
|
21
|
+
# This version introduced PEP 560 that requires a bit
|
|
22
|
+
# of extra care (we mimic what is done by __build_class__).
|
|
23
|
+
resolved_bases = types.resolve_bases(bases)
|
|
24
|
+
if resolved_bases is not bases:
|
|
25
|
+
d['__orig_bases__'] = bases
|
|
26
|
+
else:
|
|
27
|
+
resolved_bases = bases
|
|
28
|
+
return meta(name, resolved_bases, d)
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def __prepare__(cls, name, this_bases):
|
|
32
|
+
return meta.__prepare__(name, bases)
|
|
33
|
+
|
|
34
|
+
return type.__new__(metaclass, 'temporary_class', (), {})
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def add_metaclass(metaclass):
|
|
38
|
+
"""Class decorator for creating a class with a metaclass."""
|
|
39
|
+
|
|
40
|
+
def wrapper(cls):
|
|
41
|
+
orig_vars = cls.__dict__.copy()
|
|
42
|
+
slots = orig_vars.get('__slots__')
|
|
43
|
+
if slots is not None:
|
|
44
|
+
if isinstance(slots, str):
|
|
45
|
+
slots = [slots]
|
|
46
|
+
for slots_var in slots:
|
|
47
|
+
orig_vars.pop(slots_var)
|
|
48
|
+
orig_vars.pop('__dict__', None)
|
|
49
|
+
orig_vars.pop('__weakref__', None)
|
|
50
|
+
if hasattr(cls, '__qualname__'):
|
|
51
|
+
orig_vars['__qualname__'] = cls.__qualname__
|
|
52
|
+
return metaclass(cls.__name__, cls.__bases__, orig_vars)
|
|
53
|
+
|
|
54
|
+
return wrapper
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def iteritems(d, **kw):
|
|
58
|
+
return iter(d.items(**kw))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
_mini_six = {
|
|
62
|
+
"PY2": False,
|
|
63
|
+
"PY3": True,
|
|
64
|
+
"text_type": str,
|
|
65
|
+
"binary_type": bytes,
|
|
66
|
+
"string_types": (str,),
|
|
67
|
+
"integer_types": (int,),
|
|
68
|
+
"iteritems": iteritems,
|
|
69
|
+
"add_metaclass": add_metaclass,
|
|
70
|
+
"with_metaclass": with_metaclass,
|
|
71
|
+
}
|
|
72
|
+
# INLINED SIX END
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def deprecate(importable_name: str, module_name: str, *deprecated_args) -> object:
|
|
76
|
+
"""Inject import-time deprecation warnings."""
|
|
77
|
+
if not (importable_name in deprecated_args and (importable := _mini_six.get(importable_name, ...) is not ...)):
|
|
78
|
+
raise AttributeError(f"module {module_name!r} has no attribute {importable_name!r}")
|
|
79
|
+
|
|
80
|
+
# TODO Inspect and remove all calls to this function in 2.24
|
|
81
|
+
warnings.deprecate(
|
|
82
|
+
msg=f"Importing {importable_name!r} from {module_name!r} is deprecated.",
|
|
83
|
+
version="2.24",
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
return importable
|
ansible/module_utils/_text.py
CHANGED
|
@@ -1,15 +1,35 @@
|
|
|
1
1
|
# Copyright (c), Toshio Kuratomi <tkuratomi@ansible.com> 2016
|
|
2
2
|
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
|
3
3
|
|
|
4
|
-
"""
|
|
5
|
-
.. warn:: Use ansible.module_utils.common.text.converters instead.
|
|
6
|
-
"""
|
|
7
4
|
from __future__ import annotations
|
|
8
5
|
|
|
9
|
-
|
|
10
|
-
# pylint: disable=unused-import
|
|
11
|
-
import codecs
|
|
6
|
+
from ansible.module_utils.common import warnings as _warnings
|
|
12
7
|
|
|
13
|
-
from ansible.module_utils.six import PY3, text_type, binary_type
|
|
14
8
|
|
|
15
|
-
|
|
9
|
+
_mini_six = {
|
|
10
|
+
"binary_type": bytes,
|
|
11
|
+
"text_type": str,
|
|
12
|
+
"PY3": True,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def __getattr__(importable_name: str) -> object:
|
|
17
|
+
"""Inject import-time deprecation warnings."""
|
|
18
|
+
help_text: str | None = None
|
|
19
|
+
importable: object
|
|
20
|
+
if importable_name == "codecs":
|
|
21
|
+
import codecs
|
|
22
|
+
importable = codecs
|
|
23
|
+
elif importable_name in {"to_bytes", "to_native", "to_text"}:
|
|
24
|
+
from ansible.module_utils.common.text import converters
|
|
25
|
+
importable = getattr(converters, importable_name)
|
|
26
|
+
help_text = "Use ansible.module_utils.common.text.converters instead."
|
|
27
|
+
elif (importable := _mini_six.get(importable_name, ...)) is ...:
|
|
28
|
+
raise AttributeError(f"module {__name__!r} has no attribute {importable_name!r}")
|
|
29
|
+
|
|
30
|
+
_warnings.deprecate(
|
|
31
|
+
msg=f"Importing {importable_name!r} from {__name__!r} is deprecated.",
|
|
32
|
+
version="2.24",
|
|
33
|
+
help_text=help_text,
|
|
34
|
+
)
|
|
35
|
+
return importable
|
ansible/module_utils/basic.py
CHANGED
|
@@ -11,12 +11,13 @@ import typing as t
|
|
|
11
11
|
|
|
12
12
|
# Used for determining if the system is running a new enough python version
|
|
13
13
|
# and should only restrict on our documented minimum versions
|
|
14
|
-
_PY_MIN = (3,
|
|
14
|
+
_PY_MIN = (3, 9)
|
|
15
15
|
|
|
16
16
|
if sys.version_info < _PY_MIN:
|
|
17
17
|
print(json.dumps(dict(
|
|
18
18
|
failed=True,
|
|
19
|
-
msg=f"
|
|
19
|
+
msg=f"Ansible requires Python {'.'.join(map(str, _PY_MIN))} or newer on the target. "
|
|
20
|
+
f"Current version: {''.join(sys.version.splitlines())}",
|
|
20
21
|
)))
|
|
21
22
|
sys.exit(1)
|
|
22
23
|
|
|
@@ -45,6 +46,15 @@ import tempfile
|
|
|
45
46
|
import time
|
|
46
47
|
import traceback
|
|
47
48
|
|
|
49
|
+
from collections.abc import (
|
|
50
|
+
KeysView,
|
|
51
|
+
Mapping,
|
|
52
|
+
MutableMapping,
|
|
53
|
+
Sequence,
|
|
54
|
+
MutableSequence,
|
|
55
|
+
Set,
|
|
56
|
+
MutableSet,
|
|
57
|
+
)
|
|
48
58
|
from functools import reduce
|
|
49
59
|
|
|
50
60
|
try:
|
|
@@ -122,13 +132,6 @@ def _get_available_hash_algorithms():
|
|
|
122
132
|
AVAILABLE_HASH_ALGORITHMS = _get_available_hash_algorithms()
|
|
123
133
|
|
|
124
134
|
from ansible.module_utils.common import json as _json
|
|
125
|
-
|
|
126
|
-
from ansible.module_utils.six.moves.collections_abc import (
|
|
127
|
-
KeysView,
|
|
128
|
-
Mapping, MutableMapping,
|
|
129
|
-
Sequence, MutableSequence,
|
|
130
|
-
Set, MutableSet,
|
|
131
|
-
)
|
|
132
135
|
from ansible.module_utils.common.locale import get_best_parsable_locale
|
|
133
136
|
from ansible.module_utils.common.process import get_bin_path
|
|
134
137
|
from ansible.module_utils.common.file import (
|
|
@@ -2185,6 +2188,18 @@ def get_module_path():
|
|
|
2185
2188
|
return os.path.dirname(os.path.realpath(__file__))
|
|
2186
2189
|
|
|
2187
2190
|
|
|
2191
|
+
_mini_six = {
|
|
2192
|
+
"b": lambda s: s.encode("latin-1"),
|
|
2193
|
+
"PY2": False,
|
|
2194
|
+
"PY3": True,
|
|
2195
|
+
"text_type": str,
|
|
2196
|
+
"binary_type": bytes,
|
|
2197
|
+
"string_types": (str,),
|
|
2198
|
+
"integer_types": (int,),
|
|
2199
|
+
"iteritems": lambda d, **kw: iter(d.items(**kw)),
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
|
|
2188
2203
|
def __getattr__(importable_name):
|
|
2189
2204
|
"""Inject import-time deprecation warnings."""
|
|
2190
2205
|
if importable_name == 'datetime':
|
|
@@ -2202,24 +2217,12 @@ def __getattr__(importable_name):
|
|
|
2202
2217
|
elif importable_name == 'repeat':
|
|
2203
2218
|
from itertools import repeat
|
|
2204
2219
|
importable = repeat
|
|
2205
|
-
elif importable_name in {
|
|
2206
|
-
'PY2', 'PY3', 'b', 'binary_type', 'integer_types',
|
|
2207
|
-
'iteritems', 'string_types', 'text_type',
|
|
2208
|
-
}:
|
|
2209
|
-
import importlib
|
|
2210
|
-
importable = getattr(
|
|
2211
|
-
importlib.import_module('ansible.module_utils.six'),
|
|
2212
|
-
importable_name
|
|
2213
|
-
)
|
|
2214
2220
|
elif importable_name == 'map':
|
|
2215
2221
|
importable = map
|
|
2216
2222
|
elif importable_name == 'shlex_quote':
|
|
2217
2223
|
importable = shlex.quote
|
|
2218
|
-
|
|
2219
|
-
raise AttributeError(
|
|
2220
|
-
f'cannot import name {importable_name !r} '
|
|
2221
|
-
f"from '{__name__}' ({__file__ !s})"
|
|
2222
|
-
)
|
|
2224
|
+
elif (importable := _mini_six.get(importable_name, ...)) is ...:
|
|
2225
|
+
raise AttributeError(f"module {__name__!r} has no attribute {importable_name!r}")
|
|
2223
2226
|
|
|
2224
2227
|
deprecate(
|
|
2225
2228
|
msg=f"Importing '{importable_name}' from '{__name__}' is deprecated.",
|