ansible-core 2.19.0b6__py3-none-any.whl → 2.19.0b7__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 (101) hide show
  1. ansible/_internal/_templating/_jinja_bits.py +16 -1
  2. ansible/_internal/_templating/_jinja_common.py +1 -1
  3. ansible/cli/__init__.py +2 -2
  4. ansible/cli/adhoc.py +6 -3
  5. ansible/cli/console.py +1 -1
  6. ansible/cli/doc.py +2 -2
  7. ansible/config/base.yml +9 -6
  8. ansible/executor/module_common.py +8 -5
  9. ansible/executor/powershell/psrp_put_file.ps1 +1 -1
  10. ansible/executor/task_executor.py +2 -2
  11. ansible/executor/task_queue_manager.py +34 -70
  12. ansible/executor/task_result.py +1 -1
  13. ansible/galaxy/api.py +2 -2
  14. ansible/galaxy/collection/concrete_artifact_manager.py +2 -2
  15. ansible/galaxy/dependency_resolution/providers.py +3 -3
  16. ansible/inventory/group.py +6 -1
  17. ansible/inventory/host.py +6 -1
  18. ansible/module_utils/_internal/_deprecator.py +12 -1
  19. ansible/module_utils/ansible_release.py +1 -1
  20. ansible/module_utils/basic.py +14 -16
  21. ansible/module_utils/common/yaml.py +1 -1
  22. ansible/module_utils/csharp/Ansible.Basic.cs +1 -1
  23. ansible/module_utils/csharp/Ansible.Privilege.cs +2 -2
  24. ansible/module_utils/facts/hardware/base.py +1 -1
  25. ansible/module_utils/facts/other/facter.py +1 -1
  26. ansible/module_utils/facts/system/distribution.py +2 -2
  27. ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 +1 -1
  28. ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 +1 -1
  29. ansible/module_utils/powershell/Ansible.ModuleUtils.CommandUtil.psm1 +1 -1
  30. ansible/module_utils/powershell/Ansible.ModuleUtils.WebRequest.psm1 +1 -1
  31. ansible/module_utils/urls.py +1 -1
  32. ansible/modules/apt.py +9 -3
  33. ansible/modules/assemble.py +5 -3
  34. ansible/modules/expect.py +5 -5
  35. ansible/modules/hostname.py +2 -2
  36. ansible/modules/pip.py +9 -11
  37. ansible/modules/raw.py +2 -2
  38. ansible/modules/stat.py +1 -1
  39. ansible/modules/wait_for.py +10 -3
  40. ansible/parsing/mod_args.py +38 -20
  41. ansible/parsing/vault/__init__.py +3 -3
  42. ansible/playbook/base.py +0 -2
  43. ansible/playbook/helpers.py +1 -1
  44. ansible/playbook/playbook_include.py +23 -56
  45. ansible/playbook/role/__init__.py +38 -21
  46. ansible/plugins/action/__init__.py +2 -2
  47. ansible/plugins/action/assemble.py +2 -1
  48. ansible/plugins/action/assert.py +2 -2
  49. ansible/plugins/action/script.py +5 -4
  50. ansible/plugins/action/template.py +1 -1
  51. ansible/plugins/callback/__init__.py +77 -87
  52. ansible/plugins/callback/default.py +0 -3
  53. ansible/plugins/callback/junit.py +0 -6
  54. ansible/plugins/connection/ssh.py +1 -1
  55. ansible/plugins/filter/pow.yml +1 -1
  56. ansible/plugins/filter/root.yml +1 -1
  57. ansible/plugins/filter/strftime.yml +3 -3
  58. ansible/plugins/filter/to_uuid.yml +1 -1
  59. ansible/plugins/inventory/script.py +1 -1
  60. ansible/plugins/loader.py +5 -0
  61. ansible/plugins/lookup/password.py +4 -6
  62. ansible/release.py +1 -1
  63. ansible/utils/display.py +16 -26
  64. ansible/utils/path.py +1 -1
  65. ansible/utils/vars.py +4 -1
  66. ansible/vars/manager.py +6 -3
  67. ansible/vars/reserved.py +6 -4
  68. {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0b7.dist-info}/METADATA +1 -1
  69. {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0b7.dist-info}/RECORD +101 -99
  70. ansible_test/_internal/__init__.py +5 -0
  71. ansible_test/_internal/ansible_util.py +1 -1
  72. ansible_test/_internal/classification/python.py +6 -0
  73. ansible_test/_internal/cli/commands/__init__.py +0 -5
  74. ansible_test/_internal/cli/environments.py +51 -5
  75. ansible_test/_internal/commands/coverage/__init__.py +1 -1
  76. ansible_test/_internal/commands/integration/__init__.py +18 -5
  77. ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
  78. ansible_test/_internal/commands/sanity/__init__.py +3 -1
  79. ansible_test/_internal/commands/sanity/integration_aliases.py +11 -0
  80. ansible_test/_internal/commands/shell/__init__.py +43 -4
  81. ansible_test/_internal/commands/units/__init__.py +4 -1
  82. ansible_test/_internal/config.py +21 -13
  83. ansible_test/_internal/debugging.py +166 -0
  84. ansible_test/_internal/delegation.py +21 -13
  85. ansible_test/_internal/host_profiles.py +197 -6
  86. ansible_test/_internal/inventory.py +4 -0
  87. ansible_test/_internal/metadata.py +94 -4
  88. ansible_test/_internal/processes.py +80 -0
  89. ansible_test/_internal/python_requirements.py +27 -0
  90. ansible_test/_internal/target.py +8 -0
  91. ansible_test/_internal/util_common.py +13 -3
  92. ansible_test/_util/target/injector/python.py +8 -0
  93. {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0b7.dist-info}/WHEEL +0 -0
  94. {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0b7.dist-info}/entry_points.txt +0 -0
  95. {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/COPYING +0 -0
  96. {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/Apache-License.txt +0 -0
  97. {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
  98. {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/MIT-license.txt +0 -0
  99. {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/PSF-license.txt +0 -0
  100. {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
  101. {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0b7.dist-info}/top_level.txt +0 -0
@@ -19,6 +19,7 @@ from __future__ import annotations
19
19
 
20
20
  import difflib
21
21
  import functools
22
+ import inspect
22
23
  import json
23
24
  import re
24
25
  import sys
@@ -39,6 +40,7 @@ from ansible.utils.display import Display
39
40
  from ansible.vars.clean import strip_internal_keys, module_response_deepcopy
40
41
  from ansible.module_utils._internal._json._profiles import _fallback_to_str
41
42
  from ansible._internal._templating import _engine
43
+ from ansible.module_utils._internal import _deprecator
42
44
 
43
45
  import yaml
44
46
 
@@ -61,16 +63,6 @@ _SPACE_BREAK_RE = re.compile(fr' +([{_YAML_BREAK_CHARS}])')
61
63
  _T_callable = t.TypeVar("_T_callable", bound=t.Callable)
62
64
 
63
65
 
64
- def _callback_base_impl(wrapped: _T_callable) -> _T_callable:
65
- """
66
- Decorator for the no-op methods on the `CallbackBase` base class.
67
- Used to avoid unnecessary dispatch overhead to no-op base callback methods.
68
- """
69
- wrapped._base_impl = True
70
-
71
- return wrapped
72
-
73
-
74
66
  class _AnsibleCallbackDumper(_dumper.AnsibleDumper):
75
67
  def __init__(self, *args, lossy: bool = False, **kwargs):
76
68
  super().__init__(*args, **kwargs)
@@ -154,6 +146,9 @@ class CallbackBase(AnsiblePlugin):
154
146
  custom actions.
155
147
  """
156
148
 
149
+ _implemented_callback_methods: frozenset[str] = frozenset()
150
+ """Set of callback methods overridden by each subclass; used by TQM to bypass callback dispatch on no-op methods."""
151
+
157
152
  def __init__(self, display: Display | None = None, options: dict[str, t.Any] | None = None) -> None:
158
153
  super().__init__()
159
154
 
@@ -189,6 +184,48 @@ class CallbackBase(AnsiblePlugin):
189
184
  # helper for callbacks, so they don't all have to include deepcopy
190
185
  _copy_result = deepcopy
191
186
 
187
+ def _init_callback_methods(self) -> None:
188
+ """Record analysis of callback methods on each callback instance for dispatch optimization and deprecation warnings."""
189
+ implemented_callback_methods: set[str] = set()
190
+ deprecated_v1_method_overrides: set[str] = set()
191
+ plugin_file = sys.modules[type(self).__module__].__file__
192
+
193
+ if plugin_info := _deprecator._path_as_plugininfo(plugin_file):
194
+ plugin_name = plugin_info.resolved_name
195
+ else:
196
+ plugin_name = plugin_file
197
+
198
+ for base_v2_method, base_v1_method in CallbackBase._v2_v1_method_map.items():
199
+ method_name = None
200
+
201
+ if not inspect.ismethod(method := getattr(self, (v2_method_name := base_v2_method.__name__))) or method.__func__ is not base_v2_method:
202
+ implemented_callback_methods.add(v2_method_name) # v2 method directly implemented by subclass
203
+ method_name = v2_method_name
204
+ elif base_v1_method is None:
205
+ pass # no corresponding v1 method
206
+ elif not inspect.ismethod(method := getattr(self, (v1_method_name := base_v1_method.__name__))) or method.__func__ is not base_v1_method:
207
+ implemented_callback_methods.add(v2_method_name) # v1 method directly implemented by subclass
208
+ deprecated_v1_method_overrides.add(v1_method_name)
209
+ method_name = v1_method_name
210
+
211
+ if method_name and v2_method_name == 'v2_on_any':
212
+ deprecated_v1_method_overrides.discard(method_name) # avoid including v1 on_any in the v1 deprecation below
213
+
214
+ global_display.deprecated(
215
+ msg=f'The {plugin_name!r} callback plugin implements deprecated method {method_name!r}.',
216
+ version='2.23',
217
+ help_text='Use event-specific callback methods instead.',
218
+ )
219
+
220
+ self._implemented_callback_methods = frozenset(implemented_callback_methods)
221
+
222
+ if deprecated_v1_method_overrides:
223
+ global_display.deprecated(
224
+ msg=f'The {plugin_name!r} callback plugin implements the following deprecated method(s): {", ".join(sorted(deprecated_v1_method_overrides))}',
225
+ version='2.23',
226
+ help_text='Implement the `v2_*` equivalent callback method(s) instead.',
227
+ )
228
+
192
229
  def set_option(self, k, v):
193
230
  self._plugin_options[k] = C.config.get_config_value(k, plugin_type=self.plugin_type, plugin_name=self._load_name, direct={k: v})
194
231
 
@@ -316,8 +353,7 @@ class CallbackBase(AnsiblePlugin):
316
353
  if res.pop('warnings', None) and self._current_task_result and (warnings := self._current_task_result.warnings):
317
354
  # display warnings from the current task result if `warnings` was not removed from `result` (or made falsey)
318
355
  for warning in warnings:
319
- # DTFIX3: what to do about propagating wrap_text from the original display.warning call?
320
- self._display._warning(warning, wrap_text=False)
356
+ self._display._warning(warning)
321
357
 
322
358
  if res.pop('deprecations', None) and self._current_task_result and (deprecations := self._current_task_result.deprecations):
323
359
  # display deprecations from the current task result if `deprecations` was not removed from `result` (or made falsey)
@@ -327,7 +363,7 @@ class CallbackBase(AnsiblePlugin):
327
363
  def _handle_exception(self, result: _c.MutableMapping[str, t.Any], use_stderr: bool = False) -> None:
328
364
  if result.pop('exception', None) and self._current_task_result and (exception := self._current_task_result.exception):
329
365
  # display exception from the current task result if `exception` was not removed from `result` (or made falsey)
330
- self._display._error(exception, wrap_text=False, stderr=use_stderr)
366
+ self._display._error(exception, stderr=use_stderr)
331
367
 
332
368
  def _handle_warnings_and_exception(self, result: CallbackTaskResult) -> None:
333
369
  """Standardized handling of warnings/deprecations and exceptions from a task/item result."""
@@ -471,96 +507,61 @@ class CallbackBase(AnsiblePlugin):
471
507
  def set_play_context(self, play_context):
472
508
  pass
473
509
 
474
- @_callback_base_impl
475
510
  def on_any(self, *args, **kwargs):
476
511
  pass
477
512
 
478
- @_callback_base_impl
479
513
  def runner_on_failed(self, host, res, ignore_errors=False):
480
514
  pass
481
515
 
482
- @_callback_base_impl
483
516
  def runner_on_ok(self, host, res):
484
517
  pass
485
518
 
486
- @_callback_base_impl
487
519
  def runner_on_skipped(self, host, item=None):
488
520
  pass
489
521
 
490
- @_callback_base_impl
491
522
  def runner_on_unreachable(self, host, res):
492
523
  pass
493
524
 
494
- @_callback_base_impl
495
- def runner_on_no_hosts(self):
496
- pass
497
-
498
- @_callback_base_impl
499
525
  def runner_on_async_poll(self, host, res, jid, clock):
500
526
  pass
501
527
 
502
- @_callback_base_impl
503
528
  def runner_on_async_ok(self, host, res, jid):
504
529
  pass
505
530
 
506
- @_callback_base_impl
507
531
  def runner_on_async_failed(self, host, res, jid):
508
532
  pass
509
533
 
510
- @_callback_base_impl
511
534
  def playbook_on_start(self):
512
535
  pass
513
536
 
514
- @_callback_base_impl
515
537
  def playbook_on_notify(self, host, handler):
516
538
  pass
517
539
 
518
- @_callback_base_impl
519
540
  def playbook_on_no_hosts_matched(self):
520
541
  pass
521
542
 
522
- @_callback_base_impl
523
543
  def playbook_on_no_hosts_remaining(self):
524
544
  pass
525
545
 
526
- @_callback_base_impl
527
546
  def playbook_on_task_start(self, name, is_conditional):
528
547
  pass
529
548
 
530
- @_callback_base_impl
531
549
  def playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None, unsafe=None):
532
550
  pass
533
551
 
534
- @_callback_base_impl
535
- def playbook_on_setup(self):
536
- pass
537
-
538
- @_callback_base_impl
539
- def playbook_on_import_for_host(self, host, imported_file):
540
- pass
541
-
542
- @_callback_base_impl
543
- def playbook_on_not_import_for_host(self, host, missing_file):
544
- pass
545
-
546
- @_callback_base_impl
547
552
  def playbook_on_play_start(self, name):
548
553
  pass
549
554
 
550
- @_callback_base_impl
551
555
  def playbook_on_stats(self, stats):
552
556
  pass
553
557
 
554
- @_callback_base_impl
555
558
  def on_file_diff(self, host, diff):
556
559
  pass
557
560
 
558
561
  # V2 METHODS, by default they call v1 counterparts if possible
559
- @_callback_base_impl
560
562
  def v2_on_any(self, *args, **kwargs):
561
563
  self.on_any(args, kwargs)
562
564
 
563
- @_callback_base_impl
564
565
  def v2_runner_on_failed(self, result: CallbackTaskResult, ignore_errors: bool = False) -> None:
565
566
  """Process results of a failed task.
566
567
 
@@ -583,7 +584,6 @@ class CallbackBase(AnsiblePlugin):
583
584
  host = result.host.get_name()
584
585
  self.runner_on_failed(host, result.result, ignore_errors)
585
586
 
586
- @_callback_base_impl
587
587
  def v2_runner_on_ok(self, result: CallbackTaskResult) -> None:
588
588
  """Process results of a successful task.
589
589
 
@@ -596,7 +596,6 @@ class CallbackBase(AnsiblePlugin):
596
596
  host = result.host.get_name()
597
597
  self.runner_on_ok(host, result.result)
598
598
 
599
- @_callback_base_impl
600
599
  def v2_runner_on_skipped(self, result: CallbackTaskResult) -> None:
601
600
  """Process results of a skipped task.
602
601
 
@@ -610,7 +609,6 @@ class CallbackBase(AnsiblePlugin):
610
609
  host = result.host.get_name()
611
610
  self.runner_on_skipped(host, self._get_item_label(getattr(result.result, 'results', {})))
612
611
 
613
- @_callback_base_impl
614
612
  def v2_runner_on_unreachable(self, result: CallbackTaskResult) -> None:
615
613
  """Process results of a task if a target node is unreachable.
616
614
 
@@ -623,7 +621,6 @@ class CallbackBase(AnsiblePlugin):
623
621
  host = result.host.get_name()
624
622
  self.runner_on_unreachable(host, result.result)
625
623
 
626
- @_callback_base_impl
627
624
  def v2_runner_on_async_poll(self, result: CallbackTaskResult) -> None:
628
625
  """Get details about an unfinished task running in async mode.
629
626
 
@@ -642,7 +639,6 @@ class CallbackBase(AnsiblePlugin):
642
639
  clock = 0
643
640
  self.runner_on_async_poll(host, result.result, jid, clock)
644
641
 
645
- @_callback_base_impl
646
642
  def v2_runner_on_async_ok(self, result: CallbackTaskResult) -> None:
647
643
  """Process results of a successful task that ran in async mode.
648
644
 
@@ -656,7 +652,6 @@ class CallbackBase(AnsiblePlugin):
656
652
  jid = result.result.get('ansible_job_id')
657
653
  self.runner_on_async_ok(host, result.result, jid)
658
654
 
659
- @_callback_base_impl
660
655
  def v2_runner_on_async_failed(self, result: CallbackTaskResult) -> None:
661
656
  host = result.host.get_name()
662
657
  # Attempt to get the async job ID. If the job does not finish before the
@@ -666,89 +661,84 @@ class CallbackBase(AnsiblePlugin):
666
661
  jid = result.result['async_result'].get('ansible_job_id')
667
662
  self.runner_on_async_failed(host, result.result, jid)
668
663
 
669
- @_callback_base_impl
670
664
  def v2_playbook_on_start(self, playbook):
671
665
  self.playbook_on_start()
672
666
 
673
- @_callback_base_impl
674
667
  def v2_playbook_on_notify(self, handler, host):
675
668
  self.playbook_on_notify(host, handler)
676
669
 
677
- @_callback_base_impl
678
670
  def v2_playbook_on_no_hosts_matched(self):
679
671
  self.playbook_on_no_hosts_matched()
680
672
 
681
- @_callback_base_impl
682
673
  def v2_playbook_on_no_hosts_remaining(self):
683
674
  self.playbook_on_no_hosts_remaining()
684
675
 
685
- @_callback_base_impl
686
676
  def v2_playbook_on_task_start(self, task, is_conditional):
687
677
  self.playbook_on_task_start(task.name, is_conditional)
688
678
 
689
- # FIXME: not called
690
- @_callback_base_impl
691
- def v2_playbook_on_cleanup_task_start(self, task):
692
- pass # no v1 correspondence
693
-
694
- @_callback_base_impl
695
679
  def v2_playbook_on_handler_task_start(self, task):
696
680
  pass # no v1 correspondence
697
681
 
698
- @_callback_base_impl
699
682
  def v2_playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None, unsafe=None):
700
683
  self.playbook_on_vars_prompt(varname, private, prompt, encrypt, confirm, salt_size, salt, default, unsafe)
701
684
 
702
- # FIXME: not called
703
- @_callback_base_impl
704
- def v2_playbook_on_import_for_host(self, result: CallbackTaskResult, imported_file) -> None:
705
- host = result.host.get_name()
706
- self.playbook_on_import_for_host(host, imported_file)
707
-
708
- # FIXME: not called
709
- @_callback_base_impl
710
- def v2_playbook_on_not_import_for_host(self, result: CallbackTaskResult, missing_file) -> None:
711
- host = result.host.get_name()
712
- self.playbook_on_not_import_for_host(host, missing_file)
713
-
714
- @_callback_base_impl
715
685
  def v2_playbook_on_play_start(self, play):
716
686
  self.playbook_on_play_start(play.name)
717
687
 
718
- @_callback_base_impl
719
688
  def v2_playbook_on_stats(self, stats):
720
689
  self.playbook_on_stats(stats)
721
690
 
722
- @_callback_base_impl
723
691
  def v2_on_file_diff(self, result: CallbackTaskResult) -> None:
724
692
  if 'diff' in result.result:
725
693
  host = result.host.get_name()
726
694
  self.on_file_diff(host, result.result['diff'])
727
695
 
728
- @_callback_base_impl
729
696
  def v2_playbook_on_include(self, included_file):
730
697
  pass # no v1 correspondence
731
698
 
732
- @_callback_base_impl
733
699
  def v2_runner_item_on_ok(self, result: CallbackTaskResult) -> None:
734
700
  pass
735
701
 
736
- @_callback_base_impl
737
702
  def v2_runner_item_on_failed(self, result: CallbackTaskResult) -> None:
738
703
  pass
739
704
 
740
- @_callback_base_impl
741
705
  def v2_runner_item_on_skipped(self, result: CallbackTaskResult) -> None:
742
706
  pass
743
707
 
744
- @_callback_base_impl
745
708
  def v2_runner_retry(self, result: CallbackTaskResult) -> None:
746
709
  pass
747
710
 
748
- @_callback_base_impl
749
711
  def v2_runner_on_start(self, host, task):
750
712
  """Event used when host begins execution of a task
751
713
 
752
714
  .. versionadded:: 2.8
753
715
  """
754
716
  pass
717
+
718
+ _v2_v1_method_map = {
719
+ v2_on_any: on_any,
720
+ v2_on_file_diff: on_file_diff,
721
+ v2_playbook_on_handler_task_start: None,
722
+ v2_playbook_on_include: None,
723
+ v2_playbook_on_no_hosts_matched: playbook_on_no_hosts_matched,
724
+ v2_playbook_on_no_hosts_remaining: playbook_on_no_hosts_remaining,
725
+ v2_playbook_on_notify: playbook_on_notify,
726
+ v2_playbook_on_play_start: playbook_on_play_start,
727
+ v2_playbook_on_start: playbook_on_start,
728
+ v2_playbook_on_stats: playbook_on_stats,
729
+ v2_playbook_on_task_start: playbook_on_task_start,
730
+ v2_playbook_on_vars_prompt: playbook_on_vars_prompt,
731
+ v2_runner_item_on_failed: None,
732
+ v2_runner_item_on_ok: None,
733
+ v2_runner_item_on_skipped: None,
734
+ v2_runner_on_async_failed: runner_on_async_failed,
735
+ v2_runner_on_async_ok: runner_on_async_ok,
736
+ v2_runner_on_async_poll: runner_on_async_poll,
737
+ v2_runner_on_failed: runner_on_failed,
738
+ v2_runner_on_ok: runner_on_ok,
739
+ v2_runner_on_skipped: runner_on_skipped,
740
+ v2_runner_on_start: None,
741
+ v2_runner_on_unreachable: runner_on_unreachable,
742
+ v2_runner_retry: None,
743
+ }
744
+ """Internal mapping of v2 callback methods with v1 counterparts; populated after type init for deprecation warnings and bypass calculation."""
@@ -197,9 +197,6 @@ class CallbackModule(CallbackBase):
197
197
 
198
198
  self._last_task_banner = task._uuid
199
199
 
200
- def v2_playbook_on_cleanup_task_start(self, task):
201
- self._task_start(task, prefix='CLEANUP TASK')
202
-
203
200
  def v2_playbook_on_handler_task_start(self, task):
204
201
  self._task_start(task, prefix='RUNNING HANDLER')
205
202
 
@@ -300,15 +300,9 @@ class CallbackModule(CallbackBase):
300
300
  def v2_playbook_on_play_start(self, play):
301
301
  self._play_name = play.get_name()
302
302
 
303
- def v2_runner_on_no_hosts(self, task: Task) -> None:
304
- self._start_task(task)
305
-
306
303
  def v2_playbook_on_task_start(self, task: Task, is_conditional: bool) -> None:
307
304
  self._start_task(task)
308
305
 
309
- def v2_playbook_on_cleanup_task_start(self, task: Task) -> None:
310
- self._start_task(task)
311
-
312
306
  def v2_playbook_on_handler_task_start(self, task: Task) -> None:
313
307
  self._start_task(task)
314
308
 
@@ -1171,7 +1171,7 @@ class Connection(ConnectionBase):
1171
1171
 
1172
1172
  # Are we requesting privilege escalation? Right now, we may be invoked
1173
1173
  # to execute sftp/scp with sudoable=True, but we can request escalation
1174
- # only when using ssh. Otherwise we can send initial data straightaway.
1174
+ # only when using ssh. Otherwise, we can send initial data straight away.
1175
1175
 
1176
1176
  state = states.index('ready_to_send')
1177
1177
  if to_bytes(self.get_option('ssh_executable')) in cmd and sudoable:
@@ -3,7 +3,7 @@ DOCUMENTATION:
3
3
  version_added: "1.9"
4
4
  short_description: power of (math operation)
5
5
  description:
6
- - Math operation that returns the Nth power of inputed number, C(X ^ N).
6
+ - Math operation that returns the Nth power of inputted number, C(X ^ N).
7
7
  notes:
8
8
  - This is a passthrough to Python's C(math.pow).
9
9
  positional: _input, _power
@@ -3,7 +3,7 @@ DOCUMENTATION:
3
3
  version_added: "1.9"
4
4
  short_description: root of (math operation)
5
5
  description:
6
- - Math operation that returns the Nth root of inputed number C(X ^^ N).
6
+ - Math operation that returns the Nth root of inputted number C(X ^^ N).
7
7
  positional: _input, base
8
8
  options:
9
9
  _input:
@@ -1,16 +1,16 @@
1
1
  DOCUMENTATION:
2
2
  name: strftime
3
3
  version_added: "2.4"
4
- short_description: date formating
4
+ short_description: date formatting
5
5
  description:
6
- - Using Python's C(strftime) function, take a data formating string and a date/time to create a formatted date.
6
+ - Using Python's C(strftime) function, take a data formatting string and a date/time to create a formatted date.
7
7
  notes:
8
8
  - This is a passthrough to Python's C(stftime), for a complete set of formatting options go to https://strftime.org/.
9
9
  positional: _input, second, utc
10
10
  options:
11
11
  _input:
12
12
  description:
13
- - A formating string following C(stftime) conventions.
13
+ - A formatting string following C(stftime) conventions.
14
14
  - See L(the Python documentation, https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior) for a reference.
15
15
  type: str
16
16
  required: true
@@ -7,7 +7,7 @@ DOCUMENTATION:
7
7
  positional: _input, namespace
8
8
  options:
9
9
  _input:
10
- description: String to use as base fo the UUID.
10
+ description: String to use as base of the UUID.
11
11
  type: str
12
12
  required: true
13
13
  namespace:
@@ -98,7 +98,7 @@ EXAMPLES = r'''# fmt: code
98
98
  def get_api_data(namespace: str, pretty=False) -> str:
99
99
  """
100
100
  :param namespace: parameter for our custom api
101
- :param pretty: Human redable JSON vs machine readable
101
+ :param pretty: Human readable JSON vs machine readable
102
102
  :return: JSON string
103
103
  """
104
104
  found_data = list(MyInventoryAPI(namespace))
ansible/plugins/loader.py CHANGED
@@ -989,6 +989,9 @@ class PluginLoader:
989
989
  def get_with_context(self, name, *args, **kwargs) -> get_with_context_result:
990
990
  """ instantiates a plugin of the given name using arguments """
991
991
 
992
+ if not name:
993
+ raise ValueError('A non-empty plugin name is required.')
994
+
992
995
  found_in_cache = True
993
996
  class_only = kwargs.pop('class_only', False)
994
997
  collection_list = kwargs.pop('collection_list', None)
@@ -1034,6 +1037,7 @@ class PluginLoader:
1034
1037
  except AttributeError:
1035
1038
  return get_with_context_result(None, plugin_load_context)
1036
1039
  if not issubclass(obj, plugin_class):
1040
+ display.warning(f"Ignoring {self.type} plugin {resolved_type_name!r} due to missing base class {self.base_class!r}.")
1037
1041
  return get_with_context_result(None, plugin_load_context)
1038
1042
 
1039
1043
  # FIXME: update this to use the load context
@@ -1721,6 +1725,7 @@ callback_loader = PluginLoader(
1721
1725
  'ansible.plugins.callback',
1722
1726
  C.DEFAULT_CALLBACK_PLUGIN_PATH,
1723
1727
  'callback_plugins',
1728
+ required_base_class='CallbackBase',
1724
1729
  )
1725
1730
 
1726
1731
  connection_loader = PluginLoader(
@@ -126,6 +126,7 @@ _raw:
126
126
  elements: str
127
127
  """
128
128
 
129
+ import contextlib
129
130
  import os
130
131
  import string
131
132
  import time
@@ -269,15 +270,12 @@ def _get_lock(b_path):
269
270
  b_pathdir = os.path.dirname(b_path)
270
271
  lockfile_name = to_bytes("%s.ansible_lockfile" % hashlib.sha1(b_path).hexdigest())
271
272
  lockfile = os.path.join(b_pathdir, lockfile_name)
272
- if not os.path.exists(lockfile) and b_path != to_bytes('/dev/null'):
273
- try:
274
- makedirs_safe(b_pathdir, mode=0o700)
273
+ if b_path != b'/dev/null':
274
+ makedirs_safe(b_pathdir, mode=0o700)
275
+ with contextlib.suppress(FileExistsError):
275
276
  fd = os.open(lockfile, os.O_CREAT | os.O_EXCL)
276
277
  os.close(fd)
277
278
  first_process = True
278
- except OSError as e:
279
- if e.strerror != 'File exists':
280
- raise
281
279
 
282
280
  counter = 0
283
281
  # if the lock is got by other process, wait until it's released
ansible/release.py CHANGED
@@ -17,6 +17,6 @@
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- __version__ = '2.19.0b6'
20
+ __version__ = '2.19.0b7'
21
21
  __author__ = 'Ansible, Inc.'
22
22
  __codename__ = "What Is and What Should Never Be"
ansible/utils/display.py CHANGED
@@ -40,7 +40,6 @@ import secrets
40
40
  import subprocess
41
41
  import sys
42
42
  import termios
43
- import textwrap
44
43
  import threading
45
44
  import time
46
45
  import tty
@@ -329,7 +328,6 @@ class Display(metaclass=Singleton):
329
328
  self.noncow = C.ANSIBLE_COW_SELECTION
330
329
 
331
330
  self.set_cowsay_info()
332
- self._wrap_stderr = C.WRAP_STDERR
333
331
 
334
332
  if self.b_cowsay:
335
333
  try:
@@ -621,6 +619,12 @@ class Display(metaclass=Singleton):
621
619
  # collections have a resolved_name but no type
622
620
  collection = deprecator.resolved_name if deprecator else None
623
621
  plugin_fragment = ''
622
+ elif deprecator.resolved_name == 'ansible.builtin':
623
+ # core deprecations from base classes (the API) have no plugin name, only 'ansible.builtin'
624
+ plugin_type_name = str(deprecator.type) if deprecator.type is _messages.PluginType.MODULE else f'{deprecator.type} plugin'
625
+
626
+ collection = deprecator.resolved_name
627
+ plugin_fragment = f'the {plugin_type_name} API'
624
628
  else:
625
629
  parts = deprecator.resolved_name.split('.')
626
630
  plugin_name = parts[-1]
@@ -657,13 +661,6 @@ class Display(metaclass=Singleton):
657
661
 
658
662
  return _join_sentences(msg, deprecation_msg)
659
663
 
660
- def _wrap_message(self, msg: str, wrap_text: bool) -> str:
661
- if wrap_text and self._wrap_stderr:
662
- wrapped = textwrap.wrap(msg, self.columns, drop_whitespace=False)
663
- msg = "\n".join(wrapped) + "\n"
664
-
665
- return msg
666
-
667
664
  @staticmethod
668
665
  def _deduplicate(msg: str, messages: set[str]) -> bool:
669
666
  """
@@ -780,9 +777,6 @@ class Display(metaclass=Singleton):
780
777
  msg = _format_message(warning, _traceback.is_traceback_enabled(_traceback.TracebackEvent.DEPRECATED))
781
778
  msg = f'[DEPRECATION WARNING]: {msg}'
782
779
 
783
- # DTFIX3: what should we do with wrap_message?
784
- msg = self._wrap_message(msg=msg, wrap_text=True)
785
-
786
780
  if self._deduplicate(msg, self._deprecations):
787
781
  return
788
782
 
@@ -799,6 +793,8 @@ class Display(metaclass=Singleton):
799
793
  """Display a warning message."""
800
794
  _skip_stackwalk = True
801
795
 
796
+ # deprecated: description='The formatted argument has no effect.' core_version='2.23'
797
+
802
798
  # This is the pre-proxy half of the `warning` implementation.
803
799
  # Any logic that must occur on workers needs to be implemented here.
804
800
 
@@ -818,13 +814,12 @@ class Display(metaclass=Singleton):
818
814
 
819
815
  if warning_ctx := _DeferredWarningContext.current(optional=True):
820
816
  warning_ctx.capture(warning)
821
- # DTFIX3: what to do about propagating wrap_text?
822
817
  return
823
818
 
824
- self._warning(warning, wrap_text=not formatted)
819
+ self._warning(warning)
825
820
 
826
821
  @_proxy
827
- def _warning(self, warning: _messages.WarningSummary, wrap_text: bool) -> None:
822
+ def _warning(self, warning: _messages.WarningSummary) -> None:
828
823
  """Internal implementation detail, use `warning` instead."""
829
824
 
830
825
  # This is the post-proxy half of the `warning` implementation.
@@ -836,9 +831,6 @@ class Display(metaclass=Singleton):
836
831
  if self._deduplicate(msg, self._warns):
837
832
  return
838
833
 
839
- # DTFIX3: what should we do with wrap_message?
840
- msg = self._wrap_message(msg=msg, wrap_text=wrap_text)
841
-
842
834
  self.display(msg, color=C.config.get_config_value('COLOR_WARN'), stderr=True, caplevel=-2)
843
835
 
844
836
  @_proxy
@@ -927,19 +919,20 @@ class Display(metaclass=Singleton):
927
919
  warning_ctx.capture(warning)
928
920
  return
929
921
 
930
- self._warning(warning, wrap_text=False)
922
+ self._warning(warning)
931
923
 
932
924
  def error(self, msg: str | BaseException, wrap_text: bool = True, stderr: bool = True) -> None:
933
925
  """Display an error message."""
934
926
  _skip_stackwalk = True
935
927
 
928
+ # deprecated: description='The wrap_text argument has no effect.' core_version='2.23'
929
+ # deprecated: description='The stderr argument has no effect.' core_version='2.23'
930
+
936
931
  # This is the pre-proxy half of the `error` implementation.
937
932
  # Any logic that must occur on workers needs to be implemented here.
938
933
 
939
934
  if isinstance(msg, BaseException):
940
935
  event = _error_factory.ControllerEventFactory.from_exception(msg, _traceback.is_traceback_enabled(_traceback.TracebackEvent.ERROR))
941
-
942
- wrap_text = False
943
936
  else:
944
937
  event = _messages.Event(
945
938
  msg=msg,
@@ -950,10 +943,10 @@ class Display(metaclass=Singleton):
950
943
  event=event,
951
944
  )
952
945
 
953
- self._error(error, wrap_text=wrap_text, stderr=stderr)
946
+ self._error(error, stderr=True)
954
947
 
955
948
  @_proxy
956
- def _error(self, error: _messages.ErrorSummary, wrap_text: bool, stderr: bool) -> None:
949
+ def _error(self, error: _messages.ErrorSummary, stderr: bool) -> None:
957
950
  """Internal implementation detail, use `error` instead."""
958
951
 
959
952
  # This is the post-proxy half of the `error` implementation.
@@ -965,9 +958,6 @@ class Display(metaclass=Singleton):
965
958
  if self._deduplicate(msg, self._errors):
966
959
  return
967
960
 
968
- # DTFIX3: what should we do with wrap_message?
969
- msg = self._wrap_message(msg=msg, wrap_text=wrap_text)
970
-
971
961
  self.display(msg, color=C.config.get_config_value('COLOR_ERROR'), stderr=stderr, caplevel=-1)
972
962
 
973
963
  @staticmethod
ansible/utils/path.py CHANGED
@@ -102,7 +102,7 @@ def basedir(source):
102
102
  dname = os.path.dirname(source)
103
103
 
104
104
  if dname:
105
- # don't follow symlinks for basedir, enables source re-use
105
+ # don't follow symlinks for basedir, enables source reuse
106
106
  dname = os.path.abspath(dname)
107
107
 
108
108
  return to_text(dname, errors='surrogate_or_strict')