ansible-core 2.19.0b5__py3-none-any.whl → 2.19.0b6__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.
Files changed (117) hide show
  1. ansible/_internal/_ansiballz/__init__.py +0 -0
  2. ansible/_internal/_ansiballz/_builder.py +101 -0
  3. ansible/_internal/{_ansiballz.py → _ansiballz/_wrapper.py} +11 -11
  4. ansible/_internal/_templating/_jinja_bits.py +7 -4
  5. ansible/_internal/_templating/_jinja_plugins.py +5 -2
  6. ansible/_internal/_templating/_template_vars.py +72 -0
  7. ansible/_internal/_templating/_transform.py +6 -0
  8. ansible/_internal/_yaml/_constructor.py +4 -4
  9. ansible/_internal/_yaml/_dumper.py +26 -18
  10. ansible/cli/__init__.py +7 -12
  11. ansible/cli/arguments/option_helpers.py +1 -1
  12. ansible/cli/console.py +1 -1
  13. ansible/cli/doc.py +2 -2
  14. ansible/cli/inventory.py +5 -7
  15. ansible/config/base.yml +24 -0
  16. ansible/errors/__init__.py +2 -1
  17. ansible/executor/module_common.py +67 -39
  18. ansible/executor/process/worker.py +2 -2
  19. ansible/galaxy/api.py +1 -4
  20. ansible/galaxy/collection/__init__.py +1 -6
  21. ansible/galaxy/collection/concrete_artifact_manager.py +2 -8
  22. ansible/galaxy/role.py +2 -2
  23. ansible/module_utils/_internal/__init__.py +7 -4
  24. ansible/module_utils/_internal/_ansiballz/__init__.py +0 -0
  25. ansible/module_utils/_internal/_ansiballz/_extensions/__init__.py +0 -0
  26. ansible/module_utils/_internal/_ansiballz/_extensions/_coverage.py +45 -0
  27. ansible/module_utils/_internal/_ansiballz/_extensions/_pydevd.py +62 -0
  28. ansible/module_utils/_internal/{_ansiballz.py → _ansiballz/_loader.py} +10 -38
  29. ansible/module_utils/_internal/_ansiballz/_respawn.py +32 -0
  30. ansible/module_utils/_internal/_ansiballz/_respawn_wrapper.py +23 -0
  31. ansible/module_utils/_internal/_datatag/__init__.py +23 -1
  32. ansible/module_utils/_internal/_deprecator.py +27 -33
  33. ansible/module_utils/_internal/_json/_profiles/__init__.py +1 -0
  34. ansible/module_utils/_internal/_messages.py +26 -2
  35. ansible/module_utils/_internal/_plugin_info.py +14 -1
  36. ansible/module_utils/ansible_release.py +1 -1
  37. ansible/module_utils/basic.py +46 -56
  38. ansible/module_utils/common/respawn.py +4 -41
  39. ansible/module_utils/connection.py +8 -11
  40. ansible/module_utils/facts/hardware/linux.py +1 -1
  41. ansible/module_utils/facts/sysctl.py +4 -6
  42. ansible/module_utils/facts/system/caps.py +2 -2
  43. ansible/module_utils/facts/system/local.py +1 -1
  44. ansible/module_utils/facts/virtual/linux.py +1 -1
  45. ansible/module_utils/service.py +1 -1
  46. ansible/module_utils/urls.py +4 -4
  47. ansible/modules/apt_repository.py +10 -10
  48. ansible/modules/assemble.py +2 -2
  49. ansible/modules/async_wrapper.py +7 -17
  50. ansible/modules/command.py +3 -3
  51. ansible/modules/copy.py +4 -4
  52. ansible/modules/cron.py +1 -1
  53. ansible/modules/file.py +16 -17
  54. ansible/modules/find.py +3 -3
  55. ansible/modules/get_url.py +17 -0
  56. ansible/modules/git.py +9 -7
  57. ansible/modules/known_hosts.py +12 -14
  58. ansible/modules/package.py +6 -0
  59. ansible/modules/replace.py +2 -2
  60. ansible/modules/slurp.py +10 -13
  61. ansible/modules/stat.py +5 -7
  62. ansible/modules/unarchive.py +6 -6
  63. ansible/modules/user.py +1 -1
  64. ansible/modules/wait_for.py +28 -30
  65. ansible/modules/yum_repository.py +4 -3
  66. ansible/parsing/dataloader.py +2 -2
  67. ansible/parsing/vault/__init__.py +6 -10
  68. ansible/playbook/base.py +7 -2
  69. ansible/playbook/included_file.py +3 -1
  70. ansible/playbook/play_context.py +2 -0
  71. ansible/playbook/taggable.py +19 -5
  72. ansible/playbook/task.py +2 -0
  73. ansible/plugins/action/fetch.py +3 -3
  74. ansible/plugins/action/template.py +8 -2
  75. ansible/plugins/cache/__init__.py +17 -19
  76. ansible/plugins/callback/tree.py +5 -5
  77. ansible/plugins/connection/local.py +4 -4
  78. ansible/plugins/connection/paramiko_ssh.py +5 -5
  79. ansible/plugins/connection/ssh.py +8 -6
  80. ansible/plugins/connection/winrm.py +1 -1
  81. ansible/plugins/filter/core.py +19 -21
  82. ansible/plugins/filter/encryption.py +10 -2
  83. ansible/plugins/list.py +5 -4
  84. ansible/plugins/lookup/template.py +9 -4
  85. ansible/plugins/shell/powershell.py +3 -2
  86. ansible/plugins/shell/sh.py +3 -2
  87. ansible/plugins/strategy/__init__.py +3 -3
  88. ansible/plugins/test/core.py +2 -2
  89. ansible/release.py +1 -1
  90. ansible/template/__init__.py +9 -53
  91. ansible/utils/collection_loader/_collection_finder.py +3 -3
  92. ansible/utils/display.py +23 -12
  93. ansible/utils/galaxy.py +2 -2
  94. ansible/utils/hashing.py +6 -7
  95. ansible/utils/path.py +5 -7
  96. ansible/utils/py3compat.py +2 -1
  97. ansible/utils/ssh_functions.py +3 -2
  98. ansible/vars/plugins.py +3 -3
  99. {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/METADATA +1 -1
  100. {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/RECORD +117 -108
  101. ansible_test/_internal/commands/integration/coverage.py +7 -2
  102. ansible_test/_internal/host_profiles.py +62 -10
  103. ansible_test/_internal/provisioning.py +10 -4
  104. ansible_test/_internal/ssh.py +1 -5
  105. ansible_test/_internal/thread.py +2 -1
  106. ansible_test/_internal/timeout.py +1 -1
  107. ansible_test/_internal/util.py +20 -12
  108. ansible_test/_util/target/setup/requirements.py +3 -9
  109. {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/WHEEL +0 -0
  110. {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/entry_points.txt +0 -0
  111. {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/COPYING +0 -0
  112. {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/Apache-License.txt +0 -0
  113. {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
  114. {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/MIT-license.txt +0 -0
  115. {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/PSF-license.txt +0 -0
  116. {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
  117. {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/top_level.txt +0 -0
@@ -48,8 +48,9 @@ class ShellModule(ShellBase):
48
48
 
49
49
  def checksum(self, path, python_interp):
50
50
  display.deprecated(
51
- "The 'ShellModule.checksum' method is deprecated. Use 'ActionBase._execute_remote_stat()' instead.",
52
- version="2.23"
51
+ msg="The `ShellModule.checksum` method is deprecated.",
52
+ version="2.23",
53
+ help_text="Use `ActionBase._execute_remote_stat()` instead.",
53
54
  )
54
55
  # In the following test, each condition is a check and logical
55
56
  # comparison (|| or &&) that sets the rc value. Every check is run so
@@ -128,7 +128,7 @@ def results_thread_main(strategy: StrategyBase) -> None:
128
128
  strategy._workers[result.worker_id].worker_queue.put(value)
129
129
  else:
130
130
  display.warning('Received an invalid object (%s) in the result queue: %r' % (type(result), result))
131
- except (IOError, EOFError):
131
+ except (OSError, EOFError):
132
132
  break
133
133
  except queue.Empty:
134
134
  pass
@@ -402,9 +402,9 @@ class StrategyBase:
402
402
  time.sleep(0.0001)
403
403
 
404
404
  self._pending_results += 1
405
- except (EOFError, IOError, AssertionError) as e:
405
+ except (EOFError, OSError, AssertionError) as ex:
406
406
  # most likely an abort
407
- display.debug("got an error while queuing: %s" % e)
407
+ display.debug(f"got an error while queuing: {ex}")
408
408
  return
409
409
  display.debug("exiting _queue_task() for %s/%s" % (host.name, task.action))
410
410
 
@@ -175,8 +175,8 @@ def vaulted_file(value):
175
175
  try:
176
176
  with open(to_bytes(value), 'rb') as f:
177
177
  return is_encrypted_file(f)
178
- except (OSError, IOError) as e:
179
- raise errors.AnsibleFilterError(f"Cannot test if the file {value} is a vault.") from e
178
+ except OSError as ex:
179
+ raise errors.AnsibleFilterError(f"Cannot test if the file {value!r} is a vault.") from ex
180
180
 
181
181
 
182
182
  def match(value, pattern='', ignorecase=False, multiline=False):
ansible/release.py CHANGED
@@ -17,6 +17,6 @@
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- __version__ = '2.19.0b5'
20
+ __version__ = '2.19.0b6'
21
21
  __author__ = 'Ansible, Inc.'
22
22
  __codename__ = "What Is and What Should Never Be"
@@ -1,22 +1,18 @@
1
1
  from __future__ import annotations as _annotations
2
2
 
3
3
  import contextlib as _contextlib
4
- import datetime as _datetime
5
4
  import io as _io
6
5
  import os as _os
7
- import pwd as _pwd
8
- import time as _time
9
6
  import typing as _t
10
7
 
11
8
  from jinja2 import environment as _environment
12
9
 
13
10
  from ansible import _internal
14
- from ansible import constants as _constants
15
11
  from ansible import errors as _errors
16
12
  from ansible._internal._datatag import _tags, _wrappers
17
- from ansible._internal._templating import _jinja_bits, _engine, _jinja_common
13
+ from ansible._internal._templating import _jinja_bits, _engine, _jinja_common, _template_vars
14
+
18
15
  from ansible.module_utils import datatag as _module_utils_datatag
19
- from ansible.module_utils._internal import _datatag
20
16
  from ansible.utils.display import Display as _Display
21
17
 
22
18
  if _t.TYPE_CHECKING: # pragma: nocover
@@ -352,57 +348,17 @@ class Templar:
352
348
  )
353
349
 
354
350
 
355
- def generate_ansible_template_vars(path: str, fullpath: str | None = None, dest_path: str | None = None) -> dict[str, object]:
351
+ def generate_ansible_template_vars(
352
+ path: str,
353
+ fullpath: str | None = None,
354
+ dest_path: str | None = None,
355
+ ) -> dict[str, object]:
356
356
  """
357
357
  Generate and return a dictionary with variable metadata about the template specified by `fullpath`.
358
358
  If `fullpath` is `None`, `path` will be used instead.
359
359
  """
360
- if fullpath is None:
361
- fullpath = _os.path.abspath(path)
362
-
363
- template_path = fullpath
364
- template_stat = _os.stat(template_path)
365
-
366
- template_uid: int | str
367
-
368
- try:
369
- template_uid = _pwd.getpwuid(template_stat.st_uid).pw_name
370
- except KeyError:
371
- template_uid = template_stat.st_uid
372
-
373
- managed_default = _constants.config.get_config_value('DEFAULT_MANAGED_STR')
374
-
375
- managed_str = managed_default.format(
376
- # IMPORTANT: These values must be constant strings to avoid template injection.
377
- # Use Jinja template expressions where variables are needed.
378
- host="{{ template_host }}",
379
- uid="{{ template_uid }}",
380
- file="{{ template_path }}",
381
- )
382
-
383
- ansible_managed = _time.strftime(managed_str, _time.localtime(template_stat.st_mtime))
384
- # DTFIX7: this should not be tag_copy, it should either be an origin copy or some kind of derived origin
385
- ansible_managed = _datatag.AnsibleTagHelper.tag_copy(managed_default, ansible_managed)
386
- ansible_managed = trust_as_template(ansible_managed)
387
- ansible_managed = _module_utils_datatag.deprecate_value(
388
- value=ansible_managed,
389
- msg="The `ansible_managed` variable is deprecated.",
390
- help_text="Define and use a custom variable instead.",
391
- version='2.23',
392
- )
393
-
394
- temp_vars = dict(
395
- template_host=_os.uname()[1],
396
- template_path=path,
397
- template_mtime=_datetime.datetime.fromtimestamp(template_stat.st_mtime),
398
- template_uid=template_uid,
399
- template_run_date=_datetime.datetime.now(),
400
- template_destpath=dest_path,
401
- template_fullpath=fullpath,
402
- ansible_managed=ansible_managed,
403
- )
404
-
405
- return temp_vars
360
+ # deprecated description="deprecate `generate_ansible_template_vars`, collections should inline the necessary variables" core_version="2.23"
361
+ return _template_vars.generate_ansible_template_vars(path=path, fullpath=fullpath, dest_path=dest_path, include_ansible_managed=True)
406
362
 
407
363
 
408
364
  def trust_as_template(value: _TTrustable) -> _TTrustable:
@@ -1095,8 +1095,8 @@ def _get_collection_playbook_path(playbook):
1095
1095
  try:
1096
1096
  # get_collection_path
1097
1097
  pkg = import_module(acr.n_python_collection_package_name)
1098
- except (IOError, ModuleNotFoundError) as e:
1099
- # leaving e as debug target, even though not used in normal code
1098
+ except (OSError, ModuleNotFoundError) as ex:
1099
+ # leaving ex as debug target, even though not used in normal code
1100
1100
  pkg = None
1101
1101
 
1102
1102
  if pkg:
@@ -1151,7 +1151,7 @@ def _get_collection_resource_path(name, ref_type, collection_list=None):
1151
1151
  path = os.path.dirname(_to_bytes(sys.modules[acr.n_python_package_name].__file__))
1152
1152
  return resource, _to_text(path), collection_name
1153
1153
 
1154
- except (IOError, ModuleNotFoundError) as e:
1154
+ except (OSError, ModuleNotFoundError) as ex:
1155
1155
  continue
1156
1156
  except Exception as ex:
1157
1157
  # FIXME: pick out typical import errors first, then error logging
ansible/utils/display.py CHANGED
@@ -17,6 +17,7 @@
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
+ import contextlib
20
21
  import dataclasses
21
22
 
22
23
  try:
@@ -216,10 +217,22 @@ b_COW_PATHS = (
216
217
 
217
218
 
218
219
  def _synchronize_textiowrapper(tio: t.TextIO, lock: threading.RLock):
219
- # Ensure that a background thread can't hold the internal buffer lock on a file object
220
- # during a fork, which causes forked children to hang. We're using display's existing lock for
221
- # convenience (and entering the lock before a fork).
220
+ """
221
+ This decorator ensures that the supplied RLock is held before invoking the wrapped methods.
222
+ It is intended to prevent background threads from holding the Python stdout/stderr buffer lock on a file object during a fork.
223
+ Since background threads are abandoned in child forks, locks they hold are orphaned in a locked state.
224
+ Attempts to acquire an orphaned lock in this state will block forever, effectively hanging the child process on stdout/stderr writes.
225
+ The shared lock is permanently disabled immediately after a fork.
226
+ This prevents hangs in early post-fork code (e.g., stdio writes from pydevd, coverage, etc.) before user code has resumed and released the lock.
227
+ """
228
+
222
229
  def _wrap_with_lock(f, lock):
230
+ def disable_lock():
231
+ nonlocal lock
232
+ lock = contextlib.nullcontext()
233
+
234
+ os.register_at_fork(after_in_child=disable_lock)
235
+
223
236
  @wraps(f)
224
237
  def locking_wrapper(*args, **kwargs):
225
238
  with lock:
@@ -474,7 +487,7 @@ class Display(metaclass=Singleton):
474
487
  # final flush at shutdown.
475
488
  # try:
476
489
  # fileobj.flush()
477
- # except IOError as e:
490
+ # except OSError as e:
478
491
  # # Ignore EPIPE in case fileobj has been prematurely closed, eg.
479
492
  # # when piping to "head -n1"
480
493
  # if e.errno != errno.EPIPE:
@@ -603,20 +616,18 @@ class Display(metaclass=Singleton):
603
616
  else:
604
617
  removal_fragment = 'This feature will be removed'
605
618
 
606
- if not deprecator or deprecator.type == _deprecator.INDETERMINATE_DEPRECATOR.type:
607
- collection = None
608
- plugin_fragment = ''
609
- elif deprecator.type == _deprecator._COLLECTION_ONLY_TYPE:
610
- collection = deprecator.resolved_name
619
+ if not deprecator or not deprecator.type:
620
+ # indeterminate has no resolved_name or type
621
+ # collections have a resolved_name but no type
622
+ collection = deprecator.resolved_name if deprecator else None
611
623
  plugin_fragment = ''
612
624
  else:
613
625
  parts = deprecator.resolved_name.split('.')
614
626
  plugin_name = parts[-1]
615
- # DTFIX1: normalize 'modules' -> 'module' before storing it so we can eliminate the normalization here
616
- plugin_type = "module" if deprecator.type in ("module", "modules") else f'{deprecator.type} plugin'
627
+ plugin_type_name = str(deprecator.type) if deprecator.type is _messages.PluginType.MODULE else f'{deprecator.type} plugin'
617
628
 
618
629
  collection = '.'.join(parts[:2]) if len(parts) > 2 else None
619
- plugin_fragment = f'{plugin_type} {plugin_name!r}'
630
+ plugin_fragment = f'{plugin_type_name} {plugin_name!r}'
620
631
 
621
632
  if collection and plugin_fragment:
622
633
  plugin_fragment += ' in'
ansible/utils/galaxy.py CHANGED
@@ -57,8 +57,8 @@ def scm_archive_resource(src, scm='git', name=None, version='HEAD', keep_scm_met
57
57
 
58
58
  try:
59
59
  scm_path = get_bin_path(scm)
60
- except (ValueError, OSError, IOError):
61
- raise AnsibleError("could not find/use %s, it is required to continue with installing %s" % (scm, src))
60
+ except (ValueError, OSError) as ex:
61
+ raise AnsibleError(f"Could not find/use {scm!r}, it is required to continue with installing {src!r}.") from ex
62
62
 
63
63
  tempdir = tempfile.mkdtemp(dir=C.DEFAULT_LOCAL_TMP)
64
64
  clone_cmd = [scm_path, 'clone']
ansible/utils/hashing.py CHANGED
@@ -48,14 +48,13 @@ def secure_hash(filename, hash_func=sha1):
48
48
  digest = hash_func()
49
49
  blocksize = 64 * 1024
50
50
  try:
51
- infile = open(to_bytes(filename, errors='surrogate_or_strict'), 'rb')
52
- block = infile.read(blocksize)
53
- while block:
54
- digest.update(block)
51
+ with open(filename, 'rb') as infile:
55
52
  block = infile.read(blocksize)
56
- infile.close()
57
- except IOError as e:
58
- raise AnsibleError("error while accessing the file %s, error was: %s" % (filename, e))
53
+ while block:
54
+ digest.update(block)
55
+ block = infile.read(blocksize)
56
+ except OSError as ex:
57
+ raise AnsibleError(f"Error while accessing the file {filename!r}.") from ex
59
58
  return digest.hexdigest()
60
59
 
61
60
 
ansible/utils/path.py CHANGED
@@ -19,9 +19,8 @@ from __future__ import annotations
19
19
  import os
20
20
  import shutil
21
21
 
22
- from errno import EEXIST
23
22
  from ansible.errors import AnsibleError
24
- from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
23
+ from ansible.module_utils.common.text.converters import to_bytes, to_text
25
24
 
26
25
 
27
26
  __all__ = ['unfrackpath', 'makedirs_safe']
@@ -84,12 +83,11 @@ def makedirs_safe(path, mode=None):
84
83
  if not os.path.exists(b_rpath):
85
84
  try:
86
85
  if mode:
87
- os.makedirs(b_rpath, mode)
86
+ os.makedirs(b_rpath, mode, exist_ok=True)
88
87
  else:
89
- os.makedirs(b_rpath)
90
- except OSError as e:
91
- if e.errno != EEXIST:
92
- raise AnsibleError("Unable to create local directories(%s): %s" % (to_native(rpath), to_native(e)))
88
+ os.makedirs(b_rpath, exist_ok=True)
89
+ except OSError as ex:
90
+ raise AnsibleError(f"Unable to create local directories {rpath!r}.") from ex
93
91
 
94
92
 
95
93
  def basedir(source):
@@ -19,8 +19,9 @@ def __getattr__(name):
19
19
  raise AttributeError(name)
20
20
 
21
21
  display.deprecated(
22
- msg='ansible.utils.py3compat.environ is deprecated in favor of os.environ.',
22
+ msg='`ansible.utils.py3compat.environ` is deprecated.',
23
23
  version='2.20',
24
+ help_text='Use `os.environ` from the Python standard library instead.',
24
25
  )
25
26
 
26
27
  return os.environ
@@ -57,8 +57,9 @@ def set_default_transport():
57
57
  # deal with 'smart' connection .. one time ..
58
58
  if C.DEFAULT_TRANSPORT == 'smart':
59
59
  display.deprecated(
60
- msg="The 'smart' option for connections is deprecated. Set the connection plugin directly instead.",
61
- version='2.20',
60
+ msg="The `smart` option for connections is deprecated.",
61
+ version="2.20",
62
+ help_text="Set the connection plugin directly instead.",
62
63
  )
63
64
 
64
65
  # see if SSH can support ControlPersist if not use paramiko
ansible/vars/plugins.py CHANGED
@@ -35,10 +35,10 @@ def get_plugin_vars(loader, plugin, path, entities):
35
35
  if hasattr(plugin, 'get_host_vars') or hasattr(plugin, 'get_group_vars'):
36
36
  display.deprecated(
37
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
- "This plugin should be updated to inherit from BaseVarsPlugin and define "
40
- "a 'get_vars' method as the main entrypoint instead.",
38
+ "on the deprecated entrypoints `get_host_vars` and `get_group_vars`.",
41
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
42
  )
43
43
  try:
44
44
  for entity in entities:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ansible-core
3
- Version: 2.19.0b5
3
+ Version: 2.19.0b6
4
4
  Summary: Radically simple IT automation
5
5
  Author: Ansible Project
6
6
  Project-URL: Homepage, https://ansible.com/