ansible-core 2.20.0b1__py3-none-any.whl → 2.20.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.

Files changed (50) hide show
  1. ansible/cli/doc.py +3 -1
  2. ansible/collections/list.py +4 -2
  3. ansible/executor/process/worker.py +17 -11
  4. ansible/executor/task_queue_manager.py +43 -1
  5. ansible/galaxy/collection/__init__.py +7 -4
  6. ansible/galaxy/dependency_resolution/__init__.py +10 -9
  7. ansible/galaxy/dependency_resolution/dataclasses.py +86 -60
  8. ansible/galaxy/dependency_resolution/providers.py +53 -132
  9. ansible/galaxy/dependency_resolution/versioning.py +2 -4
  10. ansible/module_utils/ansible_release.py +1 -1
  11. ansible/module_utils/six/__init__.py +8 -0
  12. ansible/modules/known_hosts.py +7 -1
  13. ansible/parsing/dataloader.py +2 -2
  14. ansible/playbook/block.py +1 -3
  15. ansible/playbook/helpers.py +15 -13
  16. ansible/playbook/play.py +2 -12
  17. ansible/plugins/action/fetch.py +1 -1
  18. ansible/plugins/test/falsy.yml +1 -1
  19. ansible/plugins/test/truthy.yml +1 -1
  20. ansible/release.py +1 -1
  21. ansible/vars/manager.py +1 -2
  22. {ansible_core-2.20.0b1.dist-info → ansible_core-2.20.0rc1.dist-info}/METADATA +2 -2
  23. {ansible_core-2.20.0b1.dist-info → ansible_core-2.20.0rc1.dist-info}/RECORD +50 -50
  24. ansible_test/_data/completion/docker.txt +7 -7
  25. ansible_test/_data/requirements/ansible-test.txt +1 -1
  26. ansible_test/_data/requirements/ansible.txt +1 -1
  27. ansible_test/_data/requirements/sanity.ansible-doc.txt +2 -2
  28. ansible_test/_data/requirements/sanity.changelog.txt +1 -1
  29. ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
  30. ansible_test/_data/requirements/sanity.import.txt +1 -1
  31. ansible_test/_data/requirements/sanity.integration-aliases.txt +1 -1
  32. ansible_test/_data/requirements/sanity.pylint.txt +5 -5
  33. ansible_test/_data/requirements/sanity.runtime-metadata.txt +1 -1
  34. ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
  35. ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
  36. ansible_test/_internal/commands/sanity/pylint.py +11 -0
  37. ansible_test/_internal/coverage_util.py +1 -1
  38. ansible_test/_internal/python_requirements.py +1 -1
  39. ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +48 -45
  40. ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +9 -7
  41. ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +25 -14
  42. {ansible_core-2.20.0b1.dist-info → ansible_core-2.20.0rc1.dist-info}/WHEEL +0 -0
  43. {ansible_core-2.20.0b1.dist-info → ansible_core-2.20.0rc1.dist-info}/entry_points.txt +0 -0
  44. {ansible_core-2.20.0b1.dist-info → ansible_core-2.20.0rc1.dist-info}/licenses/COPYING +0 -0
  45. {ansible_core-2.20.0b1.dist-info → ansible_core-2.20.0rc1.dist-info}/licenses/licenses/Apache-License.txt +0 -0
  46. {ansible_core-2.20.0b1.dist-info → ansible_core-2.20.0rc1.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
  47. {ansible_core-2.20.0b1.dist-info → ansible_core-2.20.0rc1.dist-info}/licenses/licenses/MIT-license.txt +0 -0
  48. {ansible_core-2.20.0b1.dist-info → ansible_core-2.20.0rc1.dist-info}/licenses/licenses/PSF-license.txt +0 -0
  49. {ansible_core-2.20.0b1.dist-info → ansible_core-2.20.0rc1.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
  50. {ansible_core-2.20.0b1.dist-info → ansible_core-2.20.0rc1.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,
@@ -37,24 +40,24 @@ except ImportError:
37
40
 
38
41
 
39
42
  # TODO: add python requirements to ansible-test's ansible-core distribution info and remove the hardcoded lowerbound/upperbound fallback
40
- RESOLVELIB_LOWERBOUND = SemanticVersion("0.5.3")
43
+ RESOLVELIB_LOWERBOUND = SemanticVersion("0.8.0")
41
44
  RESOLVELIB_UPPERBOUND = SemanticVersion("2.0.0")
42
45
  RESOLVELIB_VERSION = SemanticVersion.from_loose_version(LooseVersion(resolvelib_version))
43
46
 
44
47
 
45
- class CollectionDependencyProviderBase(AbstractProvider):
48
+ class CollectionDependencyProvider(AbstractProvider):
46
49
  """Delegate providing a requirement interface for the resolver."""
47
50
 
48
51
  def __init__(
49
- self, # type: CollectionDependencyProviderBase
50
- apis, # type: MultiGalaxyAPIProxy
51
- concrete_artifacts_manager=None, # type: ConcreteArtifactsManager
52
- preferred_candidates=None, # type: t.Iterable[Candidate]
53
- with_deps=True, # type: bool
54
- with_pre_releases=False, # type: bool
55
- upgrade=False, # type: bool
56
- include_signatures=True, # type: bool
57
- ): # 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:
58
61
  r"""Initialize helper attributes.
59
62
 
60
63
  :param api: An instance of the multiple Galaxy APIs wrapper.
@@ -90,8 +93,10 @@ class CollectionDependencyProviderBase(AbstractProvider):
90
93
  self._upgrade = upgrade
91
94
  self._include_signatures = include_signatures
92
95
 
93
- def identify(self, requirement_or_candidate):
94
- # type: (t.Union[Candidate, Requirement]) -> str
96
+ def identify(
97
+ self,
98
+ requirement_or_candidate: Candidate | Requirement,
99
+ ) -> str:
95
100
  """Given requirement or candidate, return an identifier for it.
96
101
 
97
102
  This is used to identify a requirement or candidate, e.g.
@@ -102,8 +107,19 @@ class CollectionDependencyProviderBase(AbstractProvider):
102
107
  """
103
108
  return requirement_or_candidate.canonical_package_id
104
109
 
105
- def get_preference(self, *args, **kwargs):
106
- # 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:
107
123
  """Return sort key function return value for given requirement.
108
124
 
109
125
  This result should be based on preference that is defined as
@@ -111,38 +127,6 @@ class CollectionDependencyProviderBase(AbstractProvider):
111
127
  The lower the return value is, the more preferred this
112
128
  group of arguments is.
113
129
 
114
- resolvelib >=0.5.3, <0.7.0
115
-
116
- :param resolution: Currently pinned candidate, or ``None``.
117
-
118
- :param candidates: A list of possible candidates.
119
-
120
- :param information: A list of requirement information.
121
-
122
- Each ``information`` instance is a named tuple with two entries:
123
-
124
- * ``requirement`` specifies a requirement contributing to
125
- the current candidate list
126
-
127
- * ``parent`` specifies the candidate that provides
128
- (depended on) the requirement, or `None`
129
- to indicate a root requirement.
130
-
131
- resolvelib >=0.7.0, < 0.8.0
132
-
133
- :param identifier: The value returned by ``identify()``.
134
-
135
- :param resolutions: Mapping of identifier, candidate pairs.
136
-
137
- :param candidates: Possible candidates for the identifier.
138
- Mapping of identifier, list of candidate pairs.
139
-
140
- :param information: Requirement information of each package.
141
- Mapping of identifier, list of named tuple pairs.
142
- The named tuples have the entries ``requirement`` and ``parent``.
143
-
144
- resolvelib >=0.8.0, <= 1.0.1
145
-
146
130
  :param identifier: The value returned by ``identify()``.
147
131
 
148
132
  :param resolutions: Mapping of identifier, candidate pairs.
@@ -178,10 +162,6 @@ class CollectionDependencyProviderBase(AbstractProvider):
178
162
  the value is, the more preferred this requirement is (i.e. the
179
163
  sorting function is called with ``reverse=False``).
180
164
  """
181
- raise NotImplementedError
182
-
183
- def _get_preference(self, candidates):
184
- # type: (list[Candidate]) -> t.Union[float, int]
185
165
  if any(
186
166
  candidate in self._preferred_candidates
187
167
  for candidate in candidates
@@ -191,8 +171,12 @@ class CollectionDependencyProviderBase(AbstractProvider):
191
171
  return float('-inf')
192
172
  return len(candidates)
193
173
 
194
- def find_matches(self, *args, **kwargs):
195
- # 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]:
196
180
  r"""Find all possible candidates satisfying given requirements.
197
181
 
198
182
  This tries to get candidates based on the requirements' types.
@@ -203,32 +187,13 @@ class CollectionDependencyProviderBase(AbstractProvider):
203
187
  For a "named" requirement, Galaxy-compatible APIs are consulted
204
188
  to find concrete candidates for this requirement. If there's a
205
189
  pre-installed candidate, it's prepended in front of others.
206
-
207
- resolvelib >=0.5.3, <0.6.0
208
-
209
- :param requirements: A collection of requirements which all of \
210
- the returned candidates must match. \
211
- All requirements are guaranteed to have \
212
- the same identifier. \
213
- The collection is never empty.
214
-
215
- resolvelib >=0.6.0
216
-
217
- :param identifier: The value returned by ``identify()``.
218
-
219
- :param requirements: The requirements all returned candidates must satisfy.
220
- Mapping of identifier, iterator of requirement pairs.
221
-
222
- :param incompatibilities: Incompatible versions that must be excluded
223
- from the returned list.
224
-
225
- :returns: An iterable that orders candidates by preference, \
226
- e.g. the most preferred candidate comes first.
227
190
  """
228
- 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
+ ]
229
195
 
230
- def _find_matches(self, requirements):
231
- # type: (list[Requirement]) -> list[Candidate]
196
+ def _find_matches(self, requirements: list[Requirement]) -> list[Candidate]:
232
197
  # FIXME: The first requirement may be a Git repo followed by
233
198
  # FIXME: its cloned tmp dir. Using only the first one creates
234
199
  # FIXME: loops that prevent any further dependency exploration.
@@ -249,7 +214,10 @@ class CollectionDependencyProviderBase(AbstractProvider):
249
214
  all(self.is_satisfied_by(requirement, candidate) for requirement in requirements)
250
215
  }
251
216
  try:
252
- 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
+ )
253
221
  except TypeError as exc:
254
222
  if first_req.is_concrete_artifact:
255
223
  # Non hashable versions will cause a TypeError
@@ -292,7 +260,7 @@ class CollectionDependencyProviderBase(AbstractProvider):
292
260
 
293
261
  latest_matches = []
294
262
  signatures = []
295
- extra_signature_sources = [] # type: list[str]
263
+ extra_signature_sources: list[str] = []
296
264
 
297
265
  discarding_pre_releases_acceptable = any(
298
266
  not is_pre_release(candidate_version)
@@ -397,8 +365,11 @@ class CollectionDependencyProviderBase(AbstractProvider):
397
365
 
398
366
  return list(preinstalled_candidates) + latest_matches
399
367
 
400
- def is_satisfied_by(self, requirement, candidate):
401
- # type: (Requirement, Candidate) -> bool
368
+ def is_satisfied_by(
369
+ self,
370
+ requirement: Requirement,
371
+ candidate: Candidate,
372
+ ) -> bool:
402
373
  r"""Whether the given requirement is satisfiable by a candidate.
403
374
 
404
375
  :param requirement: A requirement that produced the `candidate`.
@@ -424,8 +395,7 @@ class CollectionDependencyProviderBase(AbstractProvider):
424
395
  requirements=requirement.ver,
425
396
  )
426
397
 
427
- def get_dependencies(self, candidate):
428
- # type: (Candidate) -> list[Candidate]
398
+ def get_dependencies(self, candidate: Candidate) -> list[Requirement]:
429
399
  r"""Get direct dependencies of a candidate.
430
400
 
431
401
  :returns: A collection of requirements that `candidate` \
@@ -456,52 +426,3 @@ class CollectionDependencyProviderBase(AbstractProvider):
456
426
  self._make_req_from_dict({'name': dep_name, 'version': dep_req})
457
427
  for dep_name, dep_req in req_map.items()
458
428
  ]
459
-
460
-
461
- # Classes to handle resolvelib API changes between minor versions for 0.X
462
- class CollectionDependencyProvider050(CollectionDependencyProviderBase):
463
- def find_matches(self, requirements): # type: ignore[override]
464
- # type: (list[Requirement]) -> list[Candidate]
465
- return self._find_matches(requirements)
466
-
467
- def get_preference(self, resolution, candidates, information): # type: ignore[override]
468
- # type: (t.Optional[Candidate], list[Candidate], list[t.NamedTuple]) -> t.Union[float, int]
469
- return self._get_preference(candidates)
470
-
471
-
472
- class CollectionDependencyProvider060(CollectionDependencyProviderBase):
473
- def find_matches(self, identifier, requirements, incompatibilities): # type: ignore[override]
474
- # type: (str, t.Mapping[str, t.Iterator[Requirement]], t.Mapping[str, t.Iterator[Requirement]]) -> list[Candidate]
475
- return [
476
- match for match in self._find_matches(list(requirements[identifier]))
477
- if not any(match.ver == incompat.ver for incompat in incompatibilities[identifier])
478
- ]
479
-
480
- def get_preference(self, resolution, candidates, information): # type: ignore[override]
481
- # type: (t.Optional[Candidate], list[Candidate], list[t.NamedTuple]) -> t.Union[float, int]
482
- return self._get_preference(candidates)
483
-
484
-
485
- class CollectionDependencyProvider070(CollectionDependencyProvider060):
486
- def get_preference(self, identifier, resolutions, candidates, information): # type: ignore[override]
487
- # type: (str, t.Mapping[str, Candidate], t.Mapping[str, t.Iterator[Candidate]], t.Iterator[t.NamedTuple]) -> t.Union[float, int]
488
- return self._get_preference(list(candidates[identifier]))
489
-
490
-
491
- class CollectionDependencyProvider080(CollectionDependencyProvider060):
492
- def get_preference(self, identifier, resolutions, candidates, information, backtrack_causes): # type: ignore[override]
493
- # type: (str, t.Mapping[str, Candidate], t.Mapping[str, t.Iterator[Candidate]], t.Iterator[t.NamedTuple], t.Sequence) -> t.Union[float, int]
494
- return self._get_preference(list(candidates[identifier]))
495
-
496
-
497
- def _get_provider(): # type () -> CollectionDependencyProviderBase
498
- if RESOLVELIB_VERSION >= SemanticVersion("0.8.0"):
499
- return CollectionDependencyProvider080
500
- if RESOLVELIB_VERSION >= SemanticVersion("0.7.0"):
501
- return CollectionDependencyProvider070
502
- if RESOLVELIB_VERSION >= SemanticVersion("0.6.0"):
503
- return CollectionDependencyProvider060
504
- return CollectionDependencyProvider050
505
-
506
-
507
- 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:
@@ -17,6 +17,6 @@
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- __version__ = '2.20.0b1'
20
+ __version__ = '2.20.0rc1'
21
21
  __author__ = 'Ansible, Inc.'
22
22
  __codename__ = "Good Times Bad Times"
@@ -33,6 +33,14 @@ import operator
33
33
  import sys
34
34
  import types
35
35
 
36
+ from ansible.module_utils.common import warnings as _warnings
37
+
38
+ _warnings.deprecate(
39
+ msg="The `ansible.module_utils.six` module is deprecated.",
40
+ help_text="Use the Python standard library equivalent instead.",
41
+ version="2.24",
42
+ )
43
+
36
44
  # The following makes it easier for us to script updates of the bundled code. It is not part of
37
45
  # upstream six
38
46
  _BUNDLED_METADATA = {"pypi_name": "six", "version": "1.17.0"}
@@ -225,7 +225,13 @@ def sanity_check(module, host, key, sshkeygen):
225
225
  rc, stdout, stderr = module.run_command(sshkeygen_command)
226
226
 
227
227
  if stdout == '': # host not found
228
- module.fail_json(msg="Host parameter does not match hashed host field in supplied key")
228
+ results = {
229
+ "msg": "Host parameter does not match hashed host field in supplied key",
230
+ "rc": rc,
231
+ }
232
+ if stderr:
233
+ results["stderr"] = stderr
234
+ module.fail_json(**results)
229
235
 
230
236
 
231
237
  def search_for_host_key(module, host, key, path, sshkeygen):
@@ -54,7 +54,7 @@ class DataLoader:
54
54
 
55
55
  def __init__(self) -> None:
56
56
 
57
- self._basedir: str = '.'
57
+ self._basedir: str = os.path.abspath('.')
58
58
 
59
59
  # NOTE: not effective with forks as the main copy does not get updated.
60
60
  # avoids rereading files
@@ -227,7 +227,7 @@ class DataLoader:
227
227
 
228
228
  def set_basedir(self, basedir: str) -> None:
229
229
  """ sets the base directory, used to find files when a relative path is given """
230
- self._basedir = basedir
230
+ self._basedir = os.path.abspath(basedir)
231
231
 
232
232
  def path_dwim(self, given: str) -> str:
233
233
  """
ansible/playbook/block.py CHANGED
@@ -17,7 +17,6 @@
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- import ansible.constants as C
21
20
  from ansible.errors import AnsibleParserError
22
21
  from ansible.module_utils.common.sentinel import Sentinel
23
22
  from ansible.playbook.attribute import NonInheritableFieldAttribute
@@ -316,8 +315,7 @@ class Block(Base, Conditional, CollectionSearch, Taggable, Notifiable, Delegatab
316
315
  filtered_block = evaluate_block(task)
317
316
  if filtered_block.has_tasks():
318
317
  tmp_list.append(filtered_block)
319
- elif ((task.action in C._ACTION_META and task.implicit) or
320
- task.evaluate_tags(self._play.only_tags, self._play.skip_tags, all_vars=all_vars)):
318
+ elif task.evaluate_tags(self._play.only_tags, self._play.skip_tags, all_vars=all_vars):
321
319
  tmp_list.append(task)
322
320
  return tmp_list
323
321
 
@@ -165,17 +165,29 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h
165
165
  subdir = 'tasks'
166
166
  if use_handlers:
167
167
  subdir = 'handlers'
168
+ try:
169
+ include_target = templar.template(task.args['_raw_params'])
170
+ except AnsibleUndefinedVariable as ex:
171
+ raise AnsibleParserError(
172
+ message=f"Error when evaluating variable in import path {task.args['_raw_params']!r}.",
173
+ help_text="When using static imports, ensure that any variables used in their names are defined in vars/vars_files\n"
174
+ "or extra-vars passed in from the command line. Static imports cannot use variables from facts or inventory\n"
175
+ "sources like group or host vars.",
176
+ obj=task_ds,
177
+ ) from ex
178
+ # FIXME this appears to be (almost?) duplicate code as in IncludedFile for include_tasks
168
179
  while parent_include is not None:
169
180
  if not isinstance(parent_include, TaskInclude):
170
181
  parent_include = parent_include._parent
171
182
  continue
172
- parent_include.post_validate(templar=templar)
173
- parent_include_dir = os.path.dirname(parent_include.args.get('_raw_params'))
183
+ if isinstance(parent_include, IncludeRole):
184
+ parent_include_dir = parent_include._role_path
185
+ else:
186
+ parent_include_dir = os.path.dirname(templar.template(parent_include.args.get('_raw_params')))
174
187
  if cumulative_path is None:
175
188
  cumulative_path = parent_include_dir
176
189
  elif not os.path.isabs(cumulative_path):
177
190
  cumulative_path = os.path.join(parent_include_dir, cumulative_path)
178
- include_target = templar.template(task.args['_raw_params'])
179
191
  if task._role:
180
192
  new_basedir = os.path.join(task._role._role_path, subdir, cumulative_path)
181
193
  include_file = loader.path_dwim_relative(new_basedir, subdir, include_target)
@@ -189,16 +201,6 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h
189
201
  parent_include = parent_include._parent
190
202
 
191
203
  if not found:
192
- try:
193
- include_target = templar.template(task.args['_raw_params'])
194
- except AnsibleUndefinedVariable as ex:
195
- raise AnsibleParserError(
196
- message=f"Error when evaluating variable in import path {task.args['_raw_params']!r}.",
197
- help_text="When using static imports, ensure that any variables used in their names are defined in vars/vars_files\n"
198
- "or extra-vars passed in from the command line. Static imports cannot use variables from facts or inventory\n"
199
- "sources like group or host vars.",
200
- obj=task_ds,
201
- ) from ex
202
204
  if task._role:
203
205
  include_file = loader.path_dwim_relative(task._role._role_path, subdir, include_target)
204
206
  else:
ansible/playbook/play.py CHANGED
@@ -314,19 +314,9 @@ class Play(Base, Taggable, CollectionSearch):
314
314
  t.args['_raw_params'] = 'flush_handlers'
315
315
  t.implicit = True
316
316
  t.set_loader(self._loader)
317
+ t.tags = ['always']
317
318
 
318
- if self.tags:
319
- # Avoid calling flush_handlers in case the whole play is skipped on tags,
320
- # this could be performance improvement since calling flush_handlers on
321
- # large inventories could be expensive even if no hosts are notified
322
- # since we call flush_handlers per host.
323
- # Block.filter_tagged_tasks ignores evaluating tags on implicit meta
324
- # tasks so we need to explicitly call Task.evaluate_tags here.
325
- t.tags = self.tags
326
- if t.evaluate_tags(self.only_tags, self.skip_tags, all_vars=self.vars):
327
- flush_block.block = [t]
328
- else:
329
- flush_block.block = [t]
319
+ flush_block.block = [t]
330
320
 
331
321
  # NOTE keep flush_handlers tasks even if a section has no regular tasks,
332
322
  # there may be notified handlers from the previous section
@@ -192,7 +192,7 @@ class ActionModule(ActionBase):
192
192
  msg="checksum mismatch", file=source, dest=dest, remote_md5sum=None,
193
193
  checksum=new_checksum, remote_checksum=remote_checksum))
194
194
  else:
195
- result.update({'changed': True, 'md5sum': new_md5, 'dest': dest,
195
+ result.update({'changed': True, 'md5sum': new_md5, 'file': source, 'dest': dest,
196
196
  'remote_md5sum': None, 'checksum': new_checksum,
197
197
  'remote_checksum': remote_checksum})
198
198
  else:
@@ -5,7 +5,7 @@ DOCUMENTATION:
5
5
  short_description: Pythonic false
6
6
  description:
7
7
  - This check is a more Python version of what is 'false'.
8
- - It is the opposite of 'truthy'.
8
+ - It is the opposite of P(ansible.builtin.truthy#test).
9
9
  options:
10
10
  _input:
11
11
  description: An expression that can be expressed in a boolean context.
@@ -20,5 +20,5 @@ EXAMPLES: |
20
20
  thisisfalse: '{{ "" is truthy }}'
21
21
  RETURN:
22
22
  _value:
23
- description: Returns V(True) if the condition is not "Python truthy", V(False) otherwise.
23
+ description: Returns V(True) if the condition is "Python truthy", V(False) otherwise.
24
24
  type: boolean
ansible/release.py CHANGED
@@ -17,6 +17,6 @@
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- __version__ = '2.20.0b1'
20
+ __version__ = '2.20.0rc1'
21
21
  __author__ = 'Ansible, Inc.'
22
22
  __codename__ = "Good Times Bad Times"
ansible/vars/manager.py CHANGED
@@ -17,7 +17,6 @@
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- import os
21
20
  import sys
22
21
  import typing as t
23
22
 
@@ -447,7 +446,7 @@ class VariableManager:
447
446
  """
448
447
 
449
448
  variables = {}
450
- variables['playbook_dir'] = os.path.abspath(self._loader.get_basedir())
449
+ variables['playbook_dir'] = self._loader.get_basedir()
451
450
  variables['ansible_playbook_python'] = sys.executable
452
451
  variables['ansible_config_file'] = C.CONFIG_FILE
453
452
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ansible-core
3
- Version: 2.20.0b1
3
+ Version: 2.20.0rc1
4
4
  Summary: Radically simple IT automation
5
5
  Author: Ansible Project
6
6
  Project-URL: Homepage, https://ansible.com/
@@ -37,7 +37,7 @@ Requires-Dist: jinja2>=3.1.0
37
37
  Requires-Dist: PyYAML>=5.1
38
38
  Requires-Dist: cryptography
39
39
  Requires-Dist: packaging
40
- Requires-Dist: resolvelib<2.0.0,>=0.5.3
40
+ Requires-Dist: resolvelib<2.0.0,>=0.8.0
41
41
  Dynamic: license-file
42
42
 
43
43
  [![PyPI version](https://img.shields.io/pypi/v/ansible-core.svg)](https://pypi.org/project/ansible-core)