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.

Files changed (215) hide show
  1. ansible/_internal/__init__.py +1 -4
  2. ansible/_internal/_ansiballz/_builder.py +1 -3
  3. ansible/_internal/_collection_proxy.py +7 -9
  4. ansible/_internal/_json/__init__.py +3 -4
  5. ansible/_internal/_templating/_engine.py +1 -1
  6. ansible/_internal/_templating/_jinja_plugins.py +1 -2
  7. ansible/_internal/_wrapt.py +105 -301
  8. ansible/cli/__init__.py +11 -10
  9. ansible/cli/adhoc.py +1 -2
  10. ansible/cli/arguments/option_helpers.py +1 -1
  11. ansible/cli/config.py +5 -6
  12. ansible/cli/doc.py +67 -67
  13. ansible/cli/galaxy.py +15 -24
  14. ansible/cli/inventory.py +0 -1
  15. ansible/cli/playbook.py +0 -1
  16. ansible/cli/pull.py +0 -1
  17. ansible/cli/scripts/ansible_connection_cli_stub.py +1 -1
  18. ansible/config/base.yml +1 -25
  19. ansible/config/manager.py +0 -2
  20. ansible/executor/play_iterator.py +42 -20
  21. ansible/executor/playbook_executor.py +0 -9
  22. ansible/executor/task_executor.py +26 -18
  23. ansible/executor/task_queue_manager.py +1 -3
  24. ansible/galaxy/api.py +33 -80
  25. ansible/galaxy/collection/__init__.py +11 -21
  26. ansible/galaxy/dependency_resolution/__init__.py +10 -9
  27. ansible/galaxy/dependency_resolution/dataclasses.py +86 -70
  28. ansible/galaxy/dependency_resolution/providers.py +54 -134
  29. ansible/galaxy/dependency_resolution/versioning.py +2 -4
  30. ansible/galaxy/role.py +1 -33
  31. ansible/inventory/manager.py +2 -3
  32. ansible/keyword_desc.yml +0 -3
  33. ansible/module_utils/_internal/_datatag/__init__.py +2 -10
  34. ansible/module_utils/_internal/_no_six.py +86 -0
  35. ansible/module_utils/_text.py +28 -8
  36. ansible/module_utils/ansible_release.py +2 -2
  37. ansible/module_utils/basic.py +26 -23
  38. ansible/module_utils/common/_collections_compat.py +11 -2
  39. ansible/module_utils/common/collections.py +8 -3
  40. ansible/module_utils/common/dict_transformations.py +1 -2
  41. ansible/module_utils/common/network.py +4 -2
  42. ansible/module_utils/common/parameters.py +32 -41
  43. ansible/module_utils/common/text/converters.py +109 -23
  44. ansible/module_utils/common/text/formatters.py +6 -2
  45. ansible/module_utils/common/validation.py +11 -9
  46. ansible/module_utils/connection.py +8 -3
  47. ansible/module_utils/facts/hardware/linux.py +23 -7
  48. ansible/module_utils/facts/hardware/netbsd.py +1 -1
  49. ansible/module_utils/facts/hardware/sunos.py +2 -1
  50. ansible/module_utils/facts/packages.py +6 -2
  51. ansible/module_utils/facts/system/distribution.py +2 -1
  52. ansible/module_utils/facts/system/env.py +6 -3
  53. ansible/module_utils/facts/system/local.py +3 -1
  54. ansible/module_utils/parsing/convert_bool.py +6 -2
  55. ansible/module_utils/service.py +2 -3
  56. ansible/module_utils/six/__init__.py +11 -6
  57. ansible/module_utils/yumdnf.py +0 -5
  58. ansible/modules/apt.py +18 -13
  59. ansible/modules/apt_repository.py +1 -1
  60. ansible/modules/assemble.py +5 -9
  61. ansible/modules/blockinfile.py +39 -23
  62. ansible/modules/cron.py +26 -35
  63. ansible/modules/deb822_repository.py +83 -12
  64. ansible/modules/dnf.py +3 -7
  65. ansible/modules/dnf5.py +4 -6
  66. ansible/modules/expect.py +0 -3
  67. ansible/modules/find.py +1 -2
  68. ansible/modules/get_url.py +1 -1
  69. ansible/modules/git.py +4 -5
  70. ansible/modules/include_vars.py +1 -1
  71. ansible/modules/known_hosts.py +7 -1
  72. ansible/modules/lineinfile.py +71 -63
  73. ansible/modules/package_facts.py +1 -1
  74. ansible/modules/pip.py +8 -2
  75. ansible/modules/replace.py +6 -6
  76. ansible/modules/service.py +3 -4
  77. ansible/modules/stat.py +20 -0
  78. ansible/modules/uri.py +9 -10
  79. ansible/modules/user.py +1 -2
  80. ansible/modules/wait_for.py +2 -2
  81. ansible/modules/wait_for_connection.py +2 -1
  82. ansible/modules/yum_repository.py +1 -16
  83. ansible/parsing/dataloader.py +24 -31
  84. ansible/parsing/vault/__init__.py +1 -2
  85. ansible/playbook/base.py +8 -56
  86. ansible/playbook/block.py +0 -60
  87. ansible/playbook/collectionsearch.py +1 -2
  88. ansible/playbook/handler.py +1 -7
  89. ansible/playbook/helpers.py +0 -7
  90. ansible/playbook/included_file.py +1 -1
  91. ansible/playbook/play.py +102 -36
  92. ansible/playbook/play_context.py +4 -0
  93. ansible/playbook/role/__init__.py +10 -65
  94. ansible/playbook/role/definition.py +3 -4
  95. ansible/playbook/role/include.py +2 -3
  96. ansible/playbook/role/metadata.py +1 -12
  97. ansible/playbook/role/requirement.py +1 -2
  98. ansible/playbook/role_include.py +1 -2
  99. ansible/playbook/taggable.py +16 -5
  100. ansible/playbook/task.py +11 -50
  101. ansible/plugins/action/__init__.py +20 -19
  102. ansible/plugins/action/add_host.py +1 -2
  103. ansible/plugins/action/fetch.py +3 -5
  104. ansible/plugins/action/group_by.py +1 -2
  105. ansible/plugins/action/include_vars.py +20 -22
  106. ansible/plugins/action/script.py +1 -3
  107. ansible/plugins/action/template.py +1 -2
  108. ansible/plugins/action/uri.py +4 -2
  109. ansible/plugins/cache/__init__.py +1 -0
  110. ansible/plugins/callback/__init__.py +13 -6
  111. ansible/plugins/connection/__init__.py +3 -7
  112. ansible/plugins/connection/local.py +2 -3
  113. ansible/plugins/connection/psrp.py +0 -2
  114. ansible/plugins/connection/ssh.py +2 -7
  115. ansible/plugins/connection/winrm.py +0 -2
  116. ansible/plugins/doc_fragments/result_format_callback.py +15 -0
  117. ansible/plugins/filter/core.py +4 -5
  118. ansible/plugins/filter/encryption.py +3 -27
  119. ansible/plugins/filter/mathstuff.py +1 -2
  120. ansible/plugins/filter/to_nice_yaml.yml +31 -3
  121. ansible/plugins/filter/to_yaml.yml +29 -12
  122. ansible/plugins/inventory/__init__.py +1 -2
  123. ansible/plugins/inventory/toml.py +3 -6
  124. ansible/plugins/inventory/yaml.py +1 -2
  125. ansible/plugins/loader.py +3 -4
  126. ansible/plugins/lookup/password.py +1 -2
  127. ansible/plugins/lookup/subelements.py +2 -3
  128. ansible/plugins/lookup/url.py +1 -1
  129. ansible/plugins/lookup/varnames.py +1 -2
  130. ansible/plugins/shell/__init__.py +9 -4
  131. ansible/plugins/shell/powershell.py +8 -24
  132. ansible/plugins/strategy/__init__.py +5 -2
  133. ansible/plugins/test/core.py +4 -1
  134. ansible/plugins/test/falsy.yml +1 -1
  135. ansible/plugins/test/regex.yml +18 -6
  136. ansible/plugins/test/truthy.yml +1 -1
  137. ansible/release.py +2 -2
  138. ansible/template/__init__.py +3 -7
  139. ansible/utils/collection_loader/_collection_config.py +5 -0
  140. ansible/utils/collection_loader/_collection_finder.py +11 -14
  141. ansible/utils/context_objects.py +7 -4
  142. ansible/utils/display.py +7 -6
  143. ansible/utils/encrypt.py +0 -5
  144. ansible/utils/helpers.py +6 -2
  145. ansible/utils/jsonrpc.py +7 -3
  146. ansible/utils/plugin_docs.py +49 -38
  147. ansible/utils/ssh_functions.py +0 -19
  148. ansible/utils/unsafe_proxy.py +7 -7
  149. ansible/vars/clean.py +2 -3
  150. ansible/vars/manager.py +28 -22
  151. ansible/vars/plugins.py +1 -31
  152. {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/METADATA +4 -4
  153. {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/RECORD +213 -214
  154. ansible_test/_data/completion/docker.txt +7 -7
  155. ansible_test/_data/completion/network.txt +0 -1
  156. ansible_test/_data/completion/remote.txt +4 -4
  157. ansible_test/_data/requirements/ansible-test.txt +1 -1
  158. ansible_test/_data/requirements/ansible.txt +1 -1
  159. ansible_test/_data/requirements/sanity.ansible-doc.txt +2 -2
  160. ansible_test/_data/requirements/sanity.changelog.txt +2 -2
  161. ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
  162. ansible_test/_data/requirements/sanity.import.txt +1 -1
  163. ansible_test/_data/requirements/sanity.integration-aliases.txt +1 -1
  164. ansible_test/_data/requirements/sanity.pep8.txt +1 -1
  165. ansible_test/_data/requirements/sanity.pylint.txt +6 -6
  166. ansible_test/_data/requirements/sanity.runtime-metadata.txt +1 -1
  167. ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
  168. ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
  169. ansible_test/_internal/cache.py +2 -5
  170. ansible_test/_internal/cli/compat.py +1 -1
  171. ansible_test/_internal/commands/coverage/combine.py +1 -3
  172. ansible_test/_internal/commands/integration/__init__.py +3 -7
  173. ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
  174. ansible_test/_internal/commands/integration/coverage.py +1 -3
  175. ansible_test/_internal/commands/integration/filters.py +5 -10
  176. ansible_test/_internal/commands/sanity/pylint.py +11 -0
  177. ansible_test/_internal/commands/sanity/validate_modules.py +1 -5
  178. ansible_test/_internal/commands/units/__init__.py +1 -13
  179. ansible_test/_internal/compat/packaging.py +2 -2
  180. ansible_test/_internal/compat/yaml.py +2 -2
  181. ansible_test/_internal/completion.py +2 -5
  182. ansible_test/_internal/config.py +2 -7
  183. ansible_test/_internal/coverage_util.py +1 -1
  184. ansible_test/_internal/delegation.py +2 -0
  185. ansible_test/_internal/docker_util.py +1 -1
  186. ansible_test/_internal/host_profiles.py +6 -11
  187. ansible_test/_internal/provider/__init__.py +2 -5
  188. ansible_test/_internal/provisioning.py +2 -5
  189. ansible_test/_internal/pypi_proxy.py +1 -1
  190. ansible_test/_internal/python_requirements.py +1 -1
  191. ansible_test/_internal/target.py +2 -6
  192. ansible_test/_internal/thread.py +1 -4
  193. ansible_test/_internal/util.py +9 -14
  194. ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +14 -19
  195. ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +48 -45
  196. ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +9 -7
  197. ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +51 -37
  198. ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +31 -18
  199. ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +1 -2
  200. ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +59 -71
  201. ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -2
  202. ansible_test/_util/target/cli/ansible_test_cli_stub.py +4 -2
  203. ansible_test/_util/target/common/constants.py +2 -2
  204. ansible_test/_util/target/setup/bootstrap.sh +0 -6
  205. ansible/utils/py3compat.py +0 -27
  206. ansible_test/_data/pytest/config/legacy.ini +0 -4
  207. {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/WHEEL +0 -0
  208. {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/entry_points.txt +0 -0
  209. {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/COPYING +0 -0
  210. {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/Apache-License.txt +0 -0
  211. {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
  212. {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/MIT-license.txt +0 -0
  213. {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/PSF-license.txt +0 -0
  214. {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
  215. {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.5.3")
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 CollectionDependencyProviderBase(AbstractProvider):
48
+ class CollectionDependencyProvider(AbstractProvider):
47
49
  """Delegate providing a requirement interface for the resolver."""
48
50
 
49
51
  def __init__(
50
- self, # type: CollectionDependencyProviderBase
51
- apis, # type: MultiGalaxyAPIProxy
52
- concrete_artifacts_manager=None, # type: ConcreteArtifactsManager
53
- preferred_candidates=None, # type: t.Iterable[Candidate]
54
- with_deps=True, # type: bool
55
- with_pre_releases=False, # type: bool
56
- upgrade=False, # type: bool
57
- include_signatures=True, # type: bool
58
- ): # type: (...) -> None
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(self, requirement_or_candidate):
95
- # type: (t.Union[Candidate, Requirement]) -> str
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(self, *args, **kwargs):
107
- # type: (t.Any, t.Any) -> t.Union[float, int]
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(self, *args, **kwargs):
196
- # type: (t.Any, t.Any) -> list[Candidate]
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
- raise NotImplementedError
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 = [] if preinstalled_candidates else self._api_proxy.get_collection_versions(first_req) # type: t.Iterable[t.Tuple[str, GalaxyAPI]]
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, string_types):
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 = [] # type: list[str]
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(self, requirement, candidate):
402
- # type: (Requirement, Candidate) -> bool
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
- if _check_working_data_filter():
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()
@@ -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, string_types):
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, string_types):
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
- else:
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
@@ -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
- # Backwards compat for people still calling it from this package
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
- from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
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
@@ -17,6 +17,6 @@
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- __version__ = '2.19.4rc1'
20
+ __version__ = '2.20.0'
21
21
  __author__ = 'Ansible, Inc.'
22
- __codename__ = "What Is and What Should Never Be"
22
+ __codename__ = "Good Times Bad Times"
@@ -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, 8)
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"ansible-core requires a minimum of Python version {'.'.join(map(str, _PY_MIN))}. Current version: {''.join(sys.version.splitlines())}",
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
- else:
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.",