ansible-core 2.19.2rc1__py3-none-any.whl → 2.20.0b1__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 (202) 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/_display_utils.py +145 -0
  5. ansible/_internal/_json/__init__.py +3 -4
  6. ansible/_internal/_templating/_engine.py +1 -1
  7. ansible/_internal/_templating/_jinja_plugins.py +1 -2
  8. ansible/_internal/_wrapt.py +105 -301
  9. ansible/cli/__init__.py +11 -10
  10. ansible/cli/adhoc.py +1 -2
  11. ansible/cli/arguments/option_helpers.py +1 -1
  12. ansible/cli/config.py +5 -6
  13. ansible/cli/doc.py +67 -67
  14. ansible/cli/galaxy.py +15 -24
  15. ansible/cli/inventory.py +0 -1
  16. ansible/cli/playbook.py +0 -1
  17. ansible/cli/pull.py +0 -1
  18. ansible/cli/scripts/ansible_connection_cli_stub.py +1 -1
  19. ansible/config/base.yml +1 -25
  20. ansible/config/manager.py +0 -2
  21. ansible/executor/play_iterator.py +42 -20
  22. ansible/executor/playbook_executor.py +0 -9
  23. ansible/executor/powershell/async_watchdog.ps1 +24 -4
  24. ansible/executor/task_executor.py +32 -22
  25. ansible/executor/task_queue_manager.py +1 -3
  26. ansible/galaxy/api.py +33 -80
  27. ansible/galaxy/collection/__init__.py +4 -17
  28. ansible/galaxy/dependency_resolution/dataclasses.py +0 -10
  29. ansible/galaxy/dependency_resolution/providers.py +1 -2
  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 +27 -24
  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/urls.py +6 -2
  58. ansible/module_utils/yumdnf.py +0 -5
  59. ansible/modules/apt.py +18 -13
  60. ansible/modules/apt_repository.py +1 -1
  61. ansible/modules/assemble.py +5 -9
  62. ansible/modules/blockinfile.py +39 -23
  63. ansible/modules/cron.py +26 -35
  64. ansible/modules/deb822_repository.py +83 -12
  65. ansible/modules/dnf.py +3 -7
  66. ansible/modules/dnf5.py +4 -6
  67. ansible/modules/expect.py +0 -3
  68. ansible/modules/find.py +1 -2
  69. ansible/modules/get_url.py +1 -1
  70. ansible/modules/git.py +4 -5
  71. ansible/modules/include_vars.py +1 -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/mod_args.py +3 -0
  85. ansible/parsing/vault/__init__.py +1 -2
  86. ansible/playbook/base.py +8 -56
  87. ansible/playbook/block.py +0 -60
  88. ansible/playbook/collectionsearch.py +1 -2
  89. ansible/playbook/handler.py +1 -7
  90. ansible/playbook/helpers.py +0 -7
  91. ansible/playbook/included_file.py +1 -1
  92. ansible/playbook/play.py +103 -37
  93. ansible/playbook/play_context.py +4 -0
  94. ansible/playbook/role/__init__.py +10 -65
  95. ansible/playbook/role/definition.py +3 -4
  96. ansible/playbook/role/include.py +2 -3
  97. ansible/playbook/role/metadata.py +1 -12
  98. ansible/playbook/role/requirement.py +1 -2
  99. ansible/playbook/role_include.py +1 -2
  100. ansible/playbook/taggable.py +16 -5
  101. ansible/playbook/task.py +51 -55
  102. ansible/plugins/action/__init__.py +20 -19
  103. ansible/plugins/action/add_host.py +1 -2
  104. ansible/plugins/action/fetch.py +2 -4
  105. ansible/plugins/action/group_by.py +1 -2
  106. ansible/plugins/action/include_vars.py +20 -22
  107. ansible/plugins/action/script.py +1 -3
  108. ansible/plugins/action/template.py +1 -2
  109. ansible/plugins/action/uri.py +4 -2
  110. ansible/plugins/cache/__init__.py +1 -0
  111. ansible/plugins/callback/__init__.py +13 -6
  112. ansible/plugins/connection/__init__.py +3 -7
  113. ansible/plugins/connection/local.py +2 -3
  114. ansible/plugins/connection/psrp.py +0 -2
  115. ansible/plugins/connection/ssh.py +2 -7
  116. ansible/plugins/connection/winrm.py +0 -2
  117. ansible/plugins/doc_fragments/result_format_callback.py +15 -0
  118. ansible/plugins/filter/core.py +4 -5
  119. ansible/plugins/filter/encryption.py +3 -27
  120. ansible/plugins/filter/mathstuff.py +1 -2
  121. ansible/plugins/filter/to_nice_yaml.yml +31 -3
  122. ansible/plugins/filter/to_yaml.yml +29 -12
  123. ansible/plugins/inventory/__init__.py +1 -2
  124. ansible/plugins/inventory/script.py +2 -1
  125. ansible/plugins/inventory/toml.py +3 -6
  126. ansible/plugins/inventory/yaml.py +1 -2
  127. ansible/plugins/list.py +10 -3
  128. ansible/plugins/loader.py +6 -6
  129. ansible/plugins/lookup/password.py +1 -2
  130. ansible/plugins/lookup/subelements.py +2 -3
  131. ansible/plugins/lookup/url.py +1 -1
  132. ansible/plugins/lookup/varnames.py +1 -2
  133. ansible/plugins/shell/__init__.py +9 -4
  134. ansible/plugins/shell/powershell.py +8 -24
  135. ansible/plugins/strategy/__init__.py +6 -3
  136. ansible/plugins/test/core.py +4 -1
  137. ansible/plugins/test/regex.yml +18 -6
  138. ansible/release.py +2 -2
  139. ansible/template/__init__.py +3 -7
  140. ansible/utils/collection_loader/_collection_config.py +5 -0
  141. ansible/utils/collection_loader/_collection_finder.py +11 -14
  142. ansible/utils/context_objects.py +7 -4
  143. ansible/utils/display.py +28 -167
  144. ansible/utils/encrypt.py +0 -5
  145. ansible/utils/helpers.py +6 -2
  146. ansible/utils/jsonrpc.py +7 -3
  147. ansible/utils/plugin_docs.py +49 -38
  148. ansible/utils/ssh_functions.py +0 -19
  149. ansible/utils/unsafe_proxy.py +7 -7
  150. ansible/vars/clean.py +2 -3
  151. ansible/vars/manager.py +27 -20
  152. ansible/vars/plugins.py +1 -31
  153. {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/METADATA +3 -3
  154. {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/RECORD +200 -200
  155. ansible_test/_data/completion/docker.txt +7 -7
  156. ansible_test/_data/completion/network.txt +0 -1
  157. ansible_test/_data/completion/remote.txt +4 -4
  158. ansible_test/_data/requirements/ansible-test.txt +1 -1
  159. ansible_test/_data/requirements/sanity.changelog.txt +1 -1
  160. ansible_test/_data/requirements/sanity.pep8.txt +1 -1
  161. ansible_test/_data/requirements/sanity.pylint.txt +4 -4
  162. ansible_test/_internal/cache.py +2 -5
  163. ansible_test/_internal/cli/compat.py +1 -1
  164. ansible_test/_internal/commands/coverage/combine.py +1 -3
  165. ansible_test/_internal/commands/integration/__init__.py +3 -7
  166. ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
  167. ansible_test/_internal/commands/integration/coverage.py +1 -3
  168. ansible_test/_internal/commands/integration/filters.py +5 -10
  169. ansible_test/_internal/commands/sanity/validate_modules.py +1 -5
  170. ansible_test/_internal/commands/units/__init__.py +1 -13
  171. ansible_test/_internal/completion.py +2 -5
  172. ansible_test/_internal/config.py +2 -7
  173. ansible_test/_internal/coverage_util.py +1 -1
  174. ansible_test/_internal/delegation.py +2 -0
  175. ansible_test/_internal/docker_util.py +1 -1
  176. ansible_test/_internal/host_profiles.py +6 -11
  177. ansible_test/_internal/provider/__init__.py +2 -5
  178. ansible_test/_internal/provisioning.py +2 -5
  179. ansible_test/_internal/pypi_proxy.py +1 -1
  180. ansible_test/_internal/target.py +2 -6
  181. ansible_test/_internal/thread.py +1 -4
  182. ansible_test/_internal/util.py +9 -14
  183. ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +14 -19
  184. ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +30 -27
  185. ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +31 -18
  186. ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +1 -2
  187. ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +59 -71
  188. ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -2
  189. ansible_test/_util/target/cli/ansible_test_cli_stub.py +4 -2
  190. ansible_test/_util/target/common/constants.py +2 -2
  191. ansible_test/_util/target/setup/bootstrap.sh +0 -6
  192. ansible/utils/py3compat.py +0 -27
  193. ansible_test/_data/pytest/config/legacy.ini +0 -4
  194. {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/WHEEL +0 -0
  195. {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/entry_points.txt +0 -0
  196. {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/COPYING +0 -0
  197. {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/Apache-License.txt +0 -0
  198. {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
  199. {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/MIT-license.txt +0 -0
  200. {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/PSF-license.txt +0 -0
  201. {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
  202. {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/top_level.txt +0 -0
@@ -11,13 +11,14 @@ import yaml
11
11
  from ansible import constants as C
12
12
  from ansible.release import __version__ as ansible_version
13
13
  from ansible.errors import AnsibleError, AnsibleParserError, AnsiblePluginNotFound
14
- from ansible.module_utils.six import string_types
14
+ from ansible.module_utils._internal import _no_six
15
15
  from ansible.module_utils.common.text.converters import to_native
16
16
  from ansible.parsing.plugin_docs import read_docstring
17
17
  from ansible.parsing.yaml.loader import AnsibleLoader
18
18
  from ansible.utils.display import Display
19
19
  from ansible._internal._datatag import _tags
20
20
 
21
+ _FRAGMENTABLE = ('DOCUMENTATION', 'RETURN')
21
22
  display = Display()
22
23
 
23
24
 
@@ -125,23 +126,30 @@ def remove_current_collection_from_versions_and_dates(fragment, collection_name,
125
126
  _process_versions_and_dates(fragment, is_module, return_docs, remove)
126
127
 
127
128
 
128
- def add_fragments(doc, filename, fragment_loader, is_module=False):
129
+ class AnsibleFragmentError(AnsibleError):
130
+ pass
131
+
132
+
133
+ def add_fragments(doc, filename, fragment_loader, is_module=False, section='DOCUMENTATION'):
134
+
135
+ if section not in _FRAGMENTABLE:
136
+ raise AnsibleError(f"Invalid fragment section ({section}) passed to render {filename}, it can only be one of {_FRAGMENTABLE!r}")
129
137
 
130
138
  fragments = doc.pop('extends_documentation_fragment', [])
131
139
 
132
- if isinstance(fragments, string_types):
140
+ if isinstance(fragments, str):
133
141
  fragments = fragments.split(',')
134
142
 
135
143
  unknown_fragments = []
136
144
 
137
- # doc_fragments are allowed to specify a fragment var other than DOCUMENTATION
145
+ # doc_fragments are allowed to specify a fragment var other than DOCUMENTATION or RETURN
138
146
  # with a . separator; this is complicated by collections-hosted doc_fragments that
139
147
  # use the same separator. Assume it's collection-hosted normally first, try to load
140
148
  # as-specified. If failure, assume the right-most component is a var, split it off,
141
149
  # and retry the load.
142
150
  for fragment_slug in fragments:
143
151
  fragment_name = fragment_slug.strip()
144
- fragment_var = 'DOCUMENTATION'
152
+ fragment_var = section
145
153
 
146
154
  fragment_class = fragment_loader.get(fragment_name)
147
155
  if fragment_class is None and '.' in fragment_slug:
@@ -157,7 +165,7 @@ def add_fragments(doc, filename, fragment_loader, is_module=False):
157
165
  # trust-tagged source propagates to loaded values; expressions and templates in config require trust
158
166
  fragment_yaml = _tags.TrustedAsTemplate().tag(getattr(fragment_class, fragment_var, None))
159
167
  if fragment_yaml is None:
160
- if fragment_var != 'DOCUMENTATION':
168
+ if fragment_var not in _FRAGMENTABLE:
161
169
  # if it's asking for something specific that's missing, that's an error
162
170
  unknown_fragments.append(fragment_slug)
163
171
  continue
@@ -168,44 +176,40 @@ def add_fragments(doc, filename, fragment_loader, is_module=False):
168
176
 
169
177
  real_fragment_name = getattr(fragment_class, 'ansible_name')
170
178
  real_collection_name = '.'.join(real_fragment_name.split('.')[0:2]) if '.' in real_fragment_name else ''
171
- add_collection_to_versions_and_dates(fragment, real_collection_name, is_module=is_module)
172
-
173
- if 'notes' in fragment:
174
- notes = fragment.pop('notes')
175
- if notes:
176
- if 'notes' not in doc:
177
- doc['notes'] = []
178
- doc['notes'].extend(notes)
179
-
180
- if 'seealso' in fragment:
181
- seealso = fragment.pop('seealso')
182
- if seealso:
183
- if 'seealso' not in doc:
184
- doc['seealso'] = []
185
- doc['seealso'].extend(seealso)
186
-
187
- if 'options' not in fragment and 'attributes' not in fragment:
188
- raise Exception("missing options or attributes in fragment (%s), possibly misformatted?: %s" % (fragment_name, filename))
189
-
190
- # ensure options themselves are directly merged
191
- for doc_key in ['options', 'attributes']:
192
- if doc_key in fragment:
193
- if doc_key in doc:
194
- try:
195
- merge_fragment(doc[doc_key], fragment.pop(doc_key))
196
- except Exception as e:
197
- raise AnsibleError("%s %s (%s) of unknown type: %s" % (to_native(e), doc_key, fragment_name, filename))
198
- else:
199
- doc[doc_key] = fragment.pop(doc_key)
179
+ add_collection_to_versions_and_dates(fragment, real_collection_name, is_module=is_module, return_docs=(section == 'RETURN'))
180
+
181
+ if section == 'DOCUMENTATION':
182
+ # notes, seealso, options and attributes entries are specificly merged, but only occur in documentation section
183
+ for doc_key in ['notes', 'seealso']:
184
+ if doc_key in fragment:
185
+ entries = fragment.pop(doc_key)
186
+ if entries:
187
+ if doc_key not in doc:
188
+ doc[doc_key] = []
189
+ doc[doc_key].extend(entries)
190
+
191
+ if 'options' not in fragment and 'attributes' not in fragment:
192
+ raise AnsibleFragmentError("missing options or attributes in fragment (%s), possibly misformatted?: %s" % (fragment_name, filename))
193
+
194
+ # ensure options themselves are directly merged
195
+ for doc_key in ['options', 'attributes']:
196
+ if doc_key in fragment:
197
+ if doc_key in doc:
198
+ try:
199
+ merge_fragment(doc[doc_key], fragment.pop(doc_key))
200
+ except Exception as e:
201
+ raise AnsibleFragmentError("%s %s (%s) of unknown type: %s" % (to_native(e), doc_key, fragment_name, filename))
202
+ else:
203
+ doc[doc_key] = fragment.pop(doc_key)
200
204
 
201
205
  # merge rest of the sections
202
206
  try:
203
207
  merge_fragment(doc, fragment)
204
208
  except Exception as e:
205
- raise AnsibleError("%s (%s) of unknown type: %s" % (to_native(e), fragment_name, filename))
209
+ raise AnsibleFragmentError("%s (%s) of unknown type: %s" % (to_native(e), fragment_name, filename))
206
210
 
207
211
  if unknown_fragments:
208
- raise AnsibleError('unknown doc_fragment(s) in file {0}: {1}'.format(filename, to_native(', '.join(unknown_fragments))))
212
+ raise AnsibleFragmentError('unknown doc_fragment(s) in file {0}: {1}'.format(filename, to_native(', '.join(unknown_fragments))))
209
213
 
210
214
 
211
215
  def get_docstring(filename, fragment_loader, verbose=False, ignore_errors=False, collection_name=None, is_module=None, plugin_type=None):
@@ -230,13 +234,16 @@ def get_docstring(filename, fragment_loader, verbose=False, ignore_errors=False,
230
234
  add_collection_to_versions_and_dates(data['doc'], collection_name, is_module=is_module)
231
235
 
232
236
  # add fragments to documentation
233
- add_fragments(data['doc'], filename, fragment_loader=fragment_loader, is_module=is_module)
237
+ add_fragments(data['doc'], filename, fragment_loader=fragment_loader, is_module=is_module, section='DOCUMENTATION')
234
238
 
235
239
  if data.get('returndocs', False):
236
240
  # add collection name to versions and dates
237
241
  if collection_name is not None:
238
242
  add_collection_to_versions_and_dates(data['returndocs'], collection_name, is_module=is_module, return_docs=True)
239
243
 
244
+ # add fragments to return
245
+ add_fragments(data['returndocs'], filename, fragment_loader=fragment_loader, is_module=is_module, section='RETURN')
246
+
240
247
  return data['doc'], data['plainexamples'], data['returndocs'], data['metadata']
241
248
 
242
249
 
@@ -352,3 +359,7 @@ def get_plugin_docs(plugin, plugin_type, loader, fragment_loader, verbose):
352
359
  docs[0]['plugin_name'] = context.resolved_fqcn
353
360
 
354
361
  return docs
362
+
363
+
364
+ def __getattr__(importable_name):
365
+ return _no_six.deprecate(importable_name, __name__, "string_types")
@@ -20,9 +20,7 @@ from __future__ import annotations
20
20
 
21
21
  import subprocess
22
22
 
23
- from ansible import constants as C
24
23
  from ansible.module_utils.common.text.converters import to_bytes
25
- from ansible.module_utils.compat.paramiko import _paramiko as paramiko
26
24
  from ansible.utils.display import Display
27
25
 
28
26
  display = Display()
@@ -50,20 +48,3 @@ def check_for_controlpersist(ssh_executable):
50
48
 
51
49
  _HAS_CONTROLPERSIST[ssh_executable] = has_cp
52
50
  return has_cp
53
-
54
-
55
- def set_default_transport():
56
-
57
- # deal with 'smart' connection .. one time ..
58
- if C.DEFAULT_TRANSPORT == 'smart':
59
- display.deprecated(
60
- msg="The `smart` option for connections is deprecated.",
61
- version="2.20",
62
- help_text="Set the connection plugin directly instead.",
63
- )
64
-
65
- # see if SSH can support ControlPersist if not use paramiko
66
- if not check_for_controlpersist('ssh') and paramiko is not None:
67
- C.DEFAULT_TRANSPORT = "paramiko"
68
- else:
69
- C.DEFAULT_TRANSPORT = "ssh"
@@ -7,17 +7,13 @@ from __future__ import annotations
7
7
 
8
8
  from collections.abc import Mapping, Set
9
9
 
10
+ from ansible.module_utils._internal import _no_six
10
11
  from ansible.module_utils.common.text.converters import to_bytes, to_text
11
12
  from ansible.module_utils.common.collections import is_sequence
12
13
  from ansible._internal._datatag._tags import TrustedAsTemplate
13
- from ansible.module_utils.six import binary_type, text_type
14
-
15
- import typing as t
16
14
 
17
15
  __all__ = ['AnsibleUnsafe', 'wrap_var']
18
16
 
19
- T = t.TypeVar('T')
20
-
21
17
 
22
18
  class AnsibleUnsafe:
23
19
  def __new__(cls, value):
@@ -66,9 +62,9 @@ def wrap_var(v):
66
62
  v = _wrap_set(v)
67
63
  elif is_sequence(v):
68
64
  v = _wrap_sequence(v)
69
- elif isinstance(v, binary_type):
65
+ elif isinstance(v, bytes):
70
66
  v = AnsibleUnsafeBytes(v)
71
- elif isinstance(v, text_type):
67
+ elif isinstance(v, str):
72
68
  v = AnsibleUnsafeText(v)
73
69
 
74
70
  return v
@@ -80,3 +76,7 @@ def to_unsafe_bytes(*args, **kwargs):
80
76
 
81
77
  def to_unsafe_text(*args, **kwargs):
82
78
  return wrap_var(to_text(*args, **kwargs))
79
+
80
+
81
+ def __getattr__(importable_name):
82
+ return _no_six.deprecate(importable_name, __name__, "binary_type", "text_type")
ansible/vars/clean.py CHANGED
@@ -10,7 +10,6 @@ from collections.abc import MutableMapping, MutableSequence
10
10
 
11
11
  from ansible import constants as C
12
12
  from ansible.errors import AnsibleError
13
- from ansible.module_utils import six
14
13
  from ansible.plugins.loader import connection_loader
15
14
  from ansible.utils.display import Display
16
15
 
@@ -48,7 +47,7 @@ def module_response_deepcopy(v):
48
47
  """
49
48
  if isinstance(v, dict):
50
49
  ret = v.copy()
51
- items = six.iteritems(ret)
50
+ items = ret.items()
52
51
  elif isinstance(v, list):
53
52
  ret = v[:]
54
53
  items = enumerate(ret)
@@ -80,7 +79,7 @@ def strip_internal_keys(dirty, exceptions=None):
80
79
 
81
80
  # listify to avoid updating dict while iterating over it
82
81
  for k in list(dirty.keys()):
83
- if isinstance(k, six.string_types):
82
+ if isinstance(k, str):
84
83
  if k.startswith('_ansible_') and k not in exceptions:
85
84
  del dirty[k]
86
85
  continue
ansible/vars/manager.py CHANGED
@@ -33,7 +33,6 @@ from ansible.inventory.host import Host
33
33
  from ansible.inventory.helpers import sort_groups, get_group_vars
34
34
  from ansible.inventory.manager import InventoryManager
35
35
  from ansible.module_utils.datatag import native_type_name
36
- from ansible.module_utils.six import text_type
37
36
  from ansible.parsing.dataloader import DataLoader
38
37
  from ansible._internal._templating._engine import TemplateEngine
39
38
  from ansible.plugins.loader import cache_loader
@@ -50,13 +49,18 @@ if t.TYPE_CHECKING:
50
49
 
51
50
  display = Display()
52
51
 
53
- # deprecated: description='enable top-level facts deprecation' core_version='2.20'
54
- # _DEPRECATE_TOP_LEVEL_FACT_TAG = _tags.Deprecated(
55
- # msg='Top-level facts are deprecated.',
56
- # version='2.24',
57
- # deprecator=_deprecator.ANSIBLE_CORE_DEPRECATOR,
58
- # help_text='Use `ansible_facts` instead.',
59
- # )
52
+ _DEPRECATE_TOP_LEVEL_FACT_TAG = _tags.Deprecated(
53
+ msg='INJECT_FACTS_AS_VARS default to `True` is deprecated, top-level facts will not be auto injected after the change.',
54
+ version='2.24',
55
+ deprecator=_deprecator.ANSIBLE_CORE_DEPRECATOR,
56
+ help_text='Use `ansible_facts["fact_name"]` (no `ansible_` prefix) instead.',
57
+ )
58
+ _DEPRECATE_VARS = _tags.Deprecated(
59
+ msg='The internal "vars" dictionary is deprecated.',
60
+ version='2.24',
61
+ deprecator=_deprecator.ANSIBLE_CORE_DEPRECATOR,
62
+ help_text='Use the `vars` and `varnames` lookups instead.',
63
+ )
60
64
 
61
65
 
62
66
  def _deprecate_top_level_fact(value: t.Any) -> t.Any:
@@ -65,9 +69,7 @@ def _deprecate_top_level_fact(value: t.Any) -> t.Any:
65
69
  The inner values are shared to aid in message de-duplication across hosts/values, and reduce intra-process memory usage.
66
70
  Unique tag instances are required to achieve the correct de-duplication within a top-level templating operation.
67
71
  """
68
- # deprecated: description='enable top-level facts deprecation' core_version='2.20'
69
- # return _DEPRECATE_TOP_LEVEL_FACT_TAG.tag(value)
70
- return value
72
+ return _DEPRECATE_TOP_LEVEL_FACT_TAG.tag(value)
71
73
 
72
74
 
73
75
  def preprocess_vars(a):
@@ -285,8 +287,7 @@ class VariableManager:
285
287
  all_vars = _combine_and_track(all_vars, _plugins_inventory([host]), "inventory host_vars for '%s'" % host)
286
288
  all_vars = _combine_and_track(all_vars, _plugins_play([host]), "playbook host_vars for '%s'" % host)
287
289
 
288
- # finally, the facts caches for this host, if it exists
289
- # TODO: cleaning of facts should eventually become part of taskresults instead of vars
290
+ # finally, the facts caches for this host, if they exist
290
291
  try:
291
292
  try:
292
293
  facts = self._fact_cache.get(host.name)
@@ -295,12 +296,16 @@ class VariableManager:
295
296
 
296
297
  all_vars |= namespace_facts(facts)
297
298
 
299
+ inject, origin = C.config.get_config_value_and_origin('INJECT_FACTS_AS_VARS')
298
300
  # push facts to main namespace
299
- if C.INJECT_FACTS_AS_VARS:
300
- deprecated_facts_vars = {k: _deprecate_top_level_fact(v) for k, v in clean_facts(facts).items()}
301
- all_vars = _combine_and_track(all_vars, deprecated_facts_vars, "facts")
301
+ if inject:
302
+ if origin == 'default':
303
+ clean_top = {k: _deprecate_top_level_fact(v) for k, v in clean_facts(facts).items()}
304
+ else:
305
+ clean_top = clean_facts(facts)
306
+ all_vars = _combine_and_track(all_vars, clean_top, "facts")
302
307
  else:
303
- # always 'promote' ansible_local
308
+ # always 'promote' ansible_local, even if empty
304
309
  all_vars = _combine_and_track(all_vars, {'ansible_local': facts.get('ansible_local', {})}, "facts")
305
310
  except KeyError:
306
311
  pass
@@ -419,8 +424,10 @@ class VariableManager:
419
424
 
420
425
  # 'vars' magic var
421
426
  if task or play:
422
- # has to be copy, otherwise recursive ref
423
- all_vars['vars'] = all_vars.copy()
427
+ all_vars['vars'] = _DEPRECATE_VARS.tag({})
428
+ for k, v in all_vars.items():
429
+ # has to be copy, otherwise recursive ref
430
+ all_vars['vars'][k] = _DEPRECATE_VARS.tag(v)
424
431
 
425
432
  display.debug("done with get_vars()")
426
433
  return all_vars
@@ -467,7 +474,7 @@ class VariableManager:
467
474
  if task._role:
468
475
  variables['role_name'] = task._role.get_name(include_role_fqcn=False)
469
476
  variables['role_path'] = task._role._role_path
470
- variables['role_uuid'] = text_type(task._role._uuid)
477
+ variables['role_uuid'] = str(task._role._uuid)
471
478
  variables['ansible_collection_name'] = task._role._role_collection
472
479
  variables['ansible_role_name'] = task._role.get_name()
473
480
 
ansible/vars/plugins.py CHANGED
@@ -8,8 +8,6 @@ import os
8
8
  from functools import lru_cache
9
9
 
10
10
  from ansible import constants as C
11
- from ansible.errors import AnsibleError
12
- from ansible.inventory.group import InventoryObjectType
13
11
  from ansible.plugins.loader import vars_loader
14
12
  from ansible.utils.display import Display
15
13
  from ansible.utils.vars import combine_vars
@@ -26,34 +24,6 @@ def _prime_vars_loader():
26
24
  vars_loader.get(plugin_name)
27
25
 
28
26
 
29
- def get_plugin_vars(loader, plugin, path, entities):
30
-
31
- data = {}
32
- try:
33
- data = plugin.get_vars(loader, path, entities)
34
- except AttributeError:
35
- if hasattr(plugin, 'get_host_vars') or hasattr(plugin, 'get_group_vars'):
36
- display.deprecated(
37
- msg=f"The vars plugin {plugin.ansible_name} from {plugin._original_path} is relying "
38
- "on the deprecated entrypoints `get_host_vars` and `get_group_vars`.",
39
- version="2.20",
40
- help_text="This plugin should be updated to inherit from `BaseVarsPlugin` and define "
41
- "a `get_vars` method as the main entrypoint instead.",
42
- )
43
- try:
44
- for entity in entities:
45
- if entity.base_type is InventoryObjectType.HOST:
46
- data |= plugin.get_host_vars(entity.name)
47
- else:
48
- data |= plugin.get_group_vars(entity.name)
49
- except AttributeError:
50
- if hasattr(plugin, 'run'):
51
- raise AnsibleError("Cannot use v1 type vars plugin %s from %s" % (plugin._load_name, plugin._original_path))
52
- else:
53
- raise AnsibleError("Invalid vars plugin %s from %s" % (plugin._load_name, plugin._original_path))
54
- return data
55
-
56
-
57
27
  # optimized for stateless plugins; non-stateless plugin instances will fall out quickly
58
28
  @lru_cache(maxsize=10)
59
29
  def _plugin_should_run(plugin, stage):
@@ -99,7 +69,7 @@ def get_vars_from_path(loader, path, entities, stage):
99
69
  if not _plugin_should_run(plugin, stage):
100
70
  continue
101
71
 
102
- if (new_vars := get_plugin_vars(loader, plugin, path, entities)) != {}:
72
+ if (new_vars := plugin.get_vars(loader, path, entities)) != {}:
103
73
  data = combine_vars(data, new_vars)
104
74
 
105
75
  return data
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ansible-core
3
- Version: 2.19.2rc1
3
+ Version: 2.20.0b1
4
4
  Summary: Radically simple IT automation
5
5
  Author: Ansible Project
6
6
  Project-URL: Homepage, https://ansible.com/
@@ -18,14 +18,14 @@ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (G
18
18
  Classifier: Natural Language :: English
19
19
  Classifier: Operating System :: POSIX
20
20
  Classifier: Programming Language :: Python :: 3
21
- Classifier: Programming Language :: Python :: 3.11
22
21
  Classifier: Programming Language :: Python :: 3.12
23
22
  Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
24
  Classifier: Programming Language :: Python :: 3 :: Only
25
25
  Classifier: Topic :: System :: Installation/Setup
26
26
  Classifier: Topic :: System :: Systems Administration
27
27
  Classifier: Topic :: Utilities
28
- Requires-Python: >=3.11
28
+ Requires-Python: >=3.12
29
29
  Description-Content-Type: text/markdown
30
30
  License-File: COPYING
31
31
  License-File: licenses/Apache-License.txt