ansible-core 2.19.0b1__py3-none-any.whl → 2.19.0b3__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.
- ansible/_internal/_ansiballz.py +1 -4
- ansible/_internal/_collection_proxy.py +47 -0
- ansible/_internal/_errors/_handler.py +4 -4
- ansible/_internal/_json/__init__.py +47 -4
- ansible/_internal/_json/_profiles/_legacy.py +2 -3
- ansible/_internal/_templating/_datatag.py +3 -4
- ansible/_internal/_templating/_engine.py +6 -1
- ansible/_internal/_templating/_jinja_bits.py +4 -4
- ansible/_internal/_templating/_jinja_plugins.py +7 -17
- ansible/cli/__init__.py +12 -5
- ansible/cli/arguments/option_helpers.py +4 -1
- ansible/cli/doc.py +14 -8
- ansible/config/base.yml +17 -20
- ansible/config/manager.py +2 -2
- ansible/constants.py +0 -62
- ansible/errors/__init__.py +6 -2
- ansible/executor/module_common.py +11 -7
- ansible/executor/process/worker.py +31 -26
- ansible/executor/task_executor.py +38 -31
- ansible/executor/task_queue_manager.py +62 -52
- ansible/executor/task_result.py +168 -72
- ansible/galaxy/api.py +1 -1
- ansible/galaxy/collection/__init__.py +3 -3
- ansible/inventory/manager.py +2 -1
- ansible/module_utils/_internal/_ansiballz.py +4 -30
- ansible/module_utils/_internal/_datatag/_tags.py +3 -25
- ansible/module_utils/_internal/_deprecator.py +134 -0
- ansible/module_utils/_internal/_plugin_info.py +25 -0
- ansible/module_utils/_internal/_validation.py +14 -0
- ansible/module_utils/ansible_release.py +1 -1
- ansible/module_utils/basic.py +68 -23
- ansible/module_utils/common/arg_spec.py +8 -3
- ansible/module_utils/common/messages.py +40 -23
- ansible/module_utils/common/process.py +0 -1
- ansible/module_utils/common/respawn.py +0 -7
- ansible/module_utils/common/warnings.py +13 -13
- ansible/module_utils/datatag.py +13 -13
- ansible/modules/async_status.py +1 -1
- ansible/modules/dnf5.py +1 -1
- ansible/modules/get_url.py +1 -1
- ansible/parsing/utils/jsonify.py +40 -0
- ansible/parsing/yaml/objects.py +16 -5
- ansible/playbook/included_file.py +25 -12
- ansible/playbook/task.py +0 -2
- ansible/plugins/__init__.py +18 -8
- ansible/plugins/action/__init__.py +6 -14
- ansible/plugins/action/gather_facts.py +2 -4
- ansible/plugins/callback/__init__.py +173 -86
- ansible/plugins/callback/default.py +79 -79
- ansible/plugins/callback/junit.py +20 -19
- ansible/plugins/callback/minimal.py +17 -17
- ansible/plugins/callback/oneline.py +23 -16
- ansible/plugins/callback/tree.py +13 -6
- ansible/plugins/connection/local.py +1 -1
- ansible/plugins/connection/paramiko_ssh.py +9 -2
- ansible/plugins/doc_fragments/action_core.py +1 -1
- ansible/plugins/filter/core.py +12 -2
- ansible/plugins/inventory/__init__.py +2 -2
- ansible/plugins/loader.py +194 -130
- ansible/plugins/lookup/url.py +2 -2
- ansible/plugins/strategy/__init__.py +76 -82
- ansible/plugins/strategy/free.py +4 -4
- ansible/plugins/strategy/linear.py +11 -9
- ansible/plugins/test/core.py +1 -1
- ansible/release.py +1 -1
- ansible/template/__init__.py +8 -6
- ansible/utils/collection_loader/_collection_meta.py +5 -3
- ansible/utils/display.py +141 -79
- ansible/utils/py3compat.py +1 -7
- ansible/utils/ssh_functions.py +4 -1
- ansible/utils/vars.py +23 -0
- ansible/vars/clean.py +1 -1
- ansible/vars/manager.py +18 -27
- ansible/vars/plugins.py +4 -4
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/METADATA +1 -1
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/RECORD +89 -85
- ansible_test/_internal/commands/sanity/pylint.py +1 -0
- ansible_test/_internal/docker_util.py +4 -3
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +475 -0
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_comment.py +137 -0
- ansible/module_utils/_internal/_dataclass_annotation_patch.py +0 -64
- ansible/module_utils/_internal/_plugin_exec_context.py +0 -49
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +0 -399
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/Apache-License.txt +0 -0
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/COPYING +0 -0
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/MIT-license.txt +0 -0
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/PSF-license.txt +0 -0
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/WHEEL +0 -0
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/simplified_bsd.txt +0 -0
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/top_level.txt +0 -0
ansible/module_utils/basic.py
CHANGED
@@ -53,9 +53,7 @@ try:
|
|
53
53
|
except ImportError:
|
54
54
|
HAS_SYSLOG = False
|
55
55
|
|
56
|
-
|
57
|
-
if t.TYPE_CHECKING:
|
58
|
-
from builtins import ellipsis
|
56
|
+
_UNSET = t.cast(t.Any, object())
|
59
57
|
|
60
58
|
try:
|
61
59
|
from systemd import journal, daemon as systemd_daemon
|
@@ -77,7 +75,7 @@ except ImportError:
|
|
77
75
|
# Python2 & 3 way to get NoneType
|
78
76
|
NoneType = type(None)
|
79
77
|
|
80
|
-
from ._internal import _traceback, _errors, _debugging
|
78
|
+
from ._internal import _traceback, _errors, _debugging, _deprecator
|
81
79
|
|
82
80
|
from .common.text.converters import (
|
83
81
|
to_native,
|
@@ -341,7 +339,7 @@ def _load_params():
|
|
341
339
|
except Exception as ex:
|
342
340
|
raise Exception("Failed to decode JSON module parameters.") from ex
|
343
341
|
|
344
|
-
if (ansible_module_args := params.get('ANSIBLE_MODULE_ARGS',
|
342
|
+
if (ansible_module_args := params.get('ANSIBLE_MODULE_ARGS', _UNSET)) is _UNSET:
|
345
343
|
raise Exception("ANSIBLE_MODULE_ARGS not provided.")
|
346
344
|
|
347
345
|
global _PARSED_MODULE_ARGS
|
@@ -511,16 +509,31 @@ class AnsibleModule(object):
|
|
511
509
|
warn(warning)
|
512
510
|
self.log('[WARNING] %s' % warning)
|
513
511
|
|
514
|
-
def deprecate(
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
512
|
+
def deprecate(
|
513
|
+
self,
|
514
|
+
msg: str,
|
515
|
+
version: str | None = None,
|
516
|
+
date: str | None = None,
|
517
|
+
collection_name: str | None = None,
|
518
|
+
*,
|
519
|
+
deprecator: _messages.PluginInfo | None = None,
|
520
|
+
help_text: str | None = None,
|
521
|
+
) -> None:
|
522
|
+
"""
|
523
|
+
Record a deprecation warning to be returned with the module result.
|
524
|
+
Most callers do not need to provide `collection_name` or `deprecator` -- but provide only one if needed.
|
525
|
+
Specify `version` or `date`, but not both.
|
526
|
+
If `date` is a string, it must be in the form `YYYY-MM-DD`.
|
527
|
+
"""
|
528
|
+
_skip_stackwalk = True
|
529
|
+
|
530
|
+
deprecate( # pylint: disable=ansible-deprecated-date-not-permitted,ansible-deprecated-unnecessary-collection-name
|
531
|
+
msg=msg,
|
532
|
+
version=version,
|
533
|
+
date=date,
|
534
|
+
deprecator=_deprecator.get_best_deprecator(deprecator=deprecator, collection_name=collection_name),
|
535
|
+
help_text=help_text,
|
536
|
+
)
|
524
537
|
|
525
538
|
def load_file_common_arguments(self, params, path=None):
|
526
539
|
"""
|
@@ -1406,6 +1419,7 @@ class AnsibleModule(object):
|
|
1406
1419
|
self.cleanup(path)
|
1407
1420
|
|
1408
1421
|
def _return_formatted(self, kwargs):
|
1422
|
+
_skip_stackwalk = True
|
1409
1423
|
|
1410
1424
|
self.add_path_info(kwargs)
|
1411
1425
|
|
@@ -1413,6 +1427,13 @@ class AnsibleModule(object):
|
|
1413
1427
|
kwargs['invocation'] = {'module_args': self.params}
|
1414
1428
|
|
1415
1429
|
if 'warnings' in kwargs:
|
1430
|
+
self.deprecate( # pylint: disable=ansible-deprecated-unnecessary-collection-name
|
1431
|
+
msg='Passing `warnings` to `exit_json` or `fail_json` is deprecated.',
|
1432
|
+
version='2.23',
|
1433
|
+
help_text='Use `AnsibleModule.warn` instead.',
|
1434
|
+
deprecator=_deprecator.ANSIBLE_CORE_DEPRECATOR,
|
1435
|
+
)
|
1436
|
+
|
1416
1437
|
if isinstance(kwargs['warnings'], list):
|
1417
1438
|
for w in kwargs['warnings']:
|
1418
1439
|
self.warn(w)
|
@@ -1424,17 +1445,38 @@ class AnsibleModule(object):
|
|
1424
1445
|
kwargs['warnings'] = warnings
|
1425
1446
|
|
1426
1447
|
if 'deprecations' in kwargs:
|
1448
|
+
self.deprecate( # pylint: disable=ansible-deprecated-unnecessary-collection-name
|
1449
|
+
msg='Passing `deprecations` to `exit_json` or `fail_json` is deprecated.',
|
1450
|
+
version='2.23',
|
1451
|
+
help_text='Use `AnsibleModule.deprecate` instead.',
|
1452
|
+
deprecator=_deprecator.ANSIBLE_CORE_DEPRECATOR,
|
1453
|
+
)
|
1454
|
+
|
1427
1455
|
if isinstance(kwargs['deprecations'], list):
|
1428
1456
|
for d in kwargs['deprecations']:
|
1429
|
-
if isinstance(d,
|
1430
|
-
self.deprecate(
|
1457
|
+
if isinstance(d, (KeysView, Sequence)) and len(d) == 2:
|
1458
|
+
self.deprecate( # pylint: disable=ansible-deprecated-unnecessary-collection-name,ansible-invalid-deprecated-version
|
1459
|
+
msg=d[0],
|
1460
|
+
version=d[1],
|
1461
|
+
deprecator=_deprecator.get_best_deprecator(),
|
1462
|
+
)
|
1431
1463
|
elif isinstance(d, Mapping):
|
1432
|
-
self.deprecate(
|
1433
|
-
|
1464
|
+
self.deprecate( # pylint: disable=ansible-deprecated-date-not-permitted,ansible-deprecated-unnecessary-collection-name
|
1465
|
+
msg=d['msg'],
|
1466
|
+
version=d.get('version'),
|
1467
|
+
date=d.get('date'),
|
1468
|
+
deprecator=_deprecator.get_best_deprecator(collection_name=d.get('collection_name')),
|
1469
|
+
)
|
1434
1470
|
else:
|
1435
|
-
self.deprecate(
|
1471
|
+
self.deprecate( # pylint: disable=ansible-deprecated-unnecessary-collection-name,ansible-deprecated-no-version
|
1472
|
+
msg=d,
|
1473
|
+
deprecator=_deprecator.get_best_deprecator(),
|
1474
|
+
)
|
1436
1475
|
else:
|
1437
|
-
self.deprecate(
|
1476
|
+
self.deprecate( # pylint: disable=ansible-deprecated-unnecessary-collection-name,ansible-deprecated-no-version
|
1477
|
+
msg=kwargs['deprecations'],
|
1478
|
+
deprecator=_deprecator.get_best_deprecator(),
|
1479
|
+
)
|
1438
1480
|
|
1439
1481
|
deprecations = get_deprecations()
|
1440
1482
|
if deprecations:
|
@@ -1454,12 +1496,13 @@ class AnsibleModule(object):
|
|
1454
1496
|
|
1455
1497
|
def exit_json(self, **kwargs) -> t.NoReturn:
|
1456
1498
|
""" return from the module, without error """
|
1499
|
+
_skip_stackwalk = True
|
1457
1500
|
|
1458
1501
|
self.do_cleanup_files()
|
1459
1502
|
self._return_formatted(kwargs)
|
1460
1503
|
sys.exit(0)
|
1461
1504
|
|
1462
|
-
def fail_json(self, msg: str, *, exception: BaseException | str |
|
1505
|
+
def fail_json(self, msg: str, *, exception: BaseException | str | None = _UNSET, **kwargs) -> t.NoReturn:
|
1463
1506
|
"""
|
1464
1507
|
Return from the module with an error message and optional exception/traceback detail.
|
1465
1508
|
A traceback will only be included in the result if error traceback capturing has been enabled.
|
@@ -1475,6 +1518,8 @@ class AnsibleModule(object):
|
|
1475
1518
|
When `exception` is not specified, a formatted traceback will be retrieved from the current exception.
|
1476
1519
|
If no exception is pending, the current call stack will be used instead.
|
1477
1520
|
"""
|
1521
|
+
_skip_stackwalk = True
|
1522
|
+
|
1478
1523
|
msg = str(msg) # coerce to str instead of raising an error due to an invalid type
|
1479
1524
|
|
1480
1525
|
kwargs.update(
|
@@ -1498,7 +1543,7 @@ class AnsibleModule(object):
|
|
1498
1543
|
|
1499
1544
|
if isinstance(exception, str):
|
1500
1545
|
formatted_traceback = exception
|
1501
|
-
elif exception is
|
1546
|
+
elif exception is _UNSET and (current_exception := t.cast(t.Optional[BaseException], sys.exc_info()[1])):
|
1502
1547
|
formatted_traceback = _traceback.maybe_extract_traceback(current_exception, _traceback.TracebackEvent.ERROR)
|
1503
1548
|
else:
|
1504
1549
|
formatted_traceback = _traceback.maybe_capture_traceback(_traceback.TracebackEvent.ERROR)
|
@@ -22,6 +22,7 @@ from ansible.module_utils.common.parameters import (
|
|
22
22
|
|
23
23
|
from ansible.module_utils.common.text.converters import to_native
|
24
24
|
from ansible.module_utils.common.warnings import deprecate, warn
|
25
|
+
from ansible.module_utils.common import messages as _messages
|
25
26
|
|
26
27
|
from ansible.module_utils.common.validation import (
|
27
28
|
check_mutually_exclusive,
|
@@ -300,9 +301,13 @@ class ModuleArgumentSpecValidator(ArgumentSpecValidator):
|
|
300
301
|
result = super(ModuleArgumentSpecValidator, self).validate(parameters)
|
301
302
|
|
302
303
|
for d in result._deprecations:
|
303
|
-
|
304
|
-
|
305
|
-
|
304
|
+
# DTFIX-FUTURE: pass an actual deprecator instead of one derived from collection_name
|
305
|
+
deprecate( # pylint: disable=ansible-deprecated-date-not-permitted,ansible-deprecated-unnecessary-collection-name
|
306
|
+
msg=d['msg'],
|
307
|
+
version=d.get('version'),
|
308
|
+
date=d.get('date'),
|
309
|
+
deprecator=_messages.PluginInfo._from_collection_name(d.get('collection_name')),
|
310
|
+
)
|
306
311
|
|
307
312
|
for w in result._warnings:
|
308
313
|
warn('Both option {option} and its alias {alias} are set.'.format(option=w['option'], alias=w['alias']))
|
@@ -13,7 +13,7 @@ import dataclasses as _dataclasses
|
|
13
13
|
# deprecated: description='typing.Self exists in Python 3.11+' python_version='3.10'
|
14
14
|
from ..compat import typing as _t
|
15
15
|
|
16
|
-
from ansible.module_utils._internal import _datatag
|
16
|
+
from ansible.module_utils._internal import _datatag, _validation
|
17
17
|
|
18
18
|
if _sys.version_info >= (3, 10):
|
19
19
|
# Using slots for reduced memory usage and improved performance.
|
@@ -27,13 +27,27 @@ else:
|
|
27
27
|
class PluginInfo(_datatag.AnsibleSerializableDataclass):
|
28
28
|
"""Information about a loaded plugin."""
|
29
29
|
|
30
|
-
requested_name: str
|
31
|
-
"""The plugin name as requested, before resolving, which may be partially or fully qualified."""
|
32
30
|
resolved_name: str
|
33
31
|
"""The resolved canonical plugin name; always fully-qualified for collection plugins."""
|
34
32
|
type: str
|
35
33
|
"""The plugin type."""
|
36
34
|
|
35
|
+
_COLLECTION_ONLY_TYPE: _t.ClassVar[str] = 'collection'
|
36
|
+
"""This is not a real plugin type. It's a placeholder for use by a `PluginInfo` instance which references a collection without a plugin."""
|
37
|
+
|
38
|
+
@classmethod
|
39
|
+
def _from_collection_name(cls, collection_name: str | None) -> _t.Self | None:
|
40
|
+
"""Returns an instance with the special `collection` type to refer to a non-plugin or ambiguous caller within a collection."""
|
41
|
+
if not collection_name:
|
42
|
+
return None
|
43
|
+
|
44
|
+
_validation.validate_collection_name(collection_name)
|
45
|
+
|
46
|
+
return cls(
|
47
|
+
resolved_name=collection_name,
|
48
|
+
type=cls._COLLECTION_ONLY_TYPE,
|
49
|
+
)
|
50
|
+
|
37
51
|
|
38
52
|
@_dataclasses.dataclass(**_dataclass_kwargs)
|
39
53
|
class Detail(_datatag.AnsibleSerializableDataclass):
|
@@ -75,34 +89,37 @@ class WarningSummary(SummaryBase):
|
|
75
89
|
class DeprecationSummary(WarningSummary):
|
76
90
|
"""Deprecation summary with details (possibly derived from an exception __cause__ chain) and an optional traceback."""
|
77
91
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
@property
|
83
|
-
def collection_name(self) -> _t.Optional[str]:
|
84
|
-
if not self.plugin:
|
85
|
-
return None
|
86
|
-
|
87
|
-
parts = self.plugin.resolved_name.split('.')
|
88
|
-
|
89
|
-
if len(parts) < 2:
|
90
|
-
return None
|
91
|
-
|
92
|
-
collection_name = '.'.join(parts[:2])
|
92
|
+
deprecator: _t.Optional[PluginInfo] = None
|
93
|
+
"""
|
94
|
+
The identifier for the content which is being deprecated.
|
95
|
+
"""
|
93
96
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
+
date: _t.Optional[str] = None
|
98
|
+
"""
|
99
|
+
The date after which a new release of `deprecator` will remove the feature described by `msg`.
|
100
|
+
Ignored if `deprecator` is not provided.
|
101
|
+
"""
|
97
102
|
|
98
|
-
|
103
|
+
version: _t.Optional[str] = None
|
104
|
+
"""
|
105
|
+
The version of `deprecator` which will remove the feature described by `msg`.
|
106
|
+
Ignored if `deprecator` is not provided.
|
107
|
+
Ignored if `date` is provided.
|
108
|
+
"""
|
99
109
|
|
100
110
|
def _as_simple_dict(self) -> _t.Dict[str, _t.Any]:
|
101
111
|
"""Returns a dictionary representation of the deprecation object in the format exposed to playbooks."""
|
112
|
+
from ansible.module_utils._internal._deprecator import INDETERMINATE_DEPRECATOR # circular import from messages
|
113
|
+
|
114
|
+
if self.deprecator and self.deprecator != INDETERMINATE_DEPRECATOR:
|
115
|
+
collection_name = '.'.join(self.deprecator.resolved_name.split('.')[:2])
|
116
|
+
else:
|
117
|
+
collection_name = None
|
118
|
+
|
102
119
|
result = self._as_dict()
|
103
120
|
result.update(
|
104
121
|
msg=self._format(),
|
105
|
-
collection_name=
|
122
|
+
collection_name=collection_name,
|
106
123
|
)
|
107
124
|
|
108
125
|
return result
|
@@ -3,14 +3,12 @@
|
|
3
3
|
|
4
4
|
from __future__ import annotations
|
5
5
|
|
6
|
-
import dataclasses
|
7
6
|
import os
|
8
7
|
import pathlib
|
9
8
|
import subprocess
|
10
9
|
import sys
|
11
10
|
import typing as t
|
12
11
|
|
13
|
-
from ansible.module_utils._internal import _plugin_exec_context
|
14
12
|
from ansible.module_utils.common.text.converters import to_bytes
|
15
13
|
|
16
14
|
_ANSIBLE_PARENT_PATH = pathlib.Path(__file__).parents[3]
|
@@ -99,7 +97,6 @@ if __name__ == '__main__':
|
|
99
97
|
|
100
98
|
json_params = {json_params!r}
|
101
99
|
profile = {profile!r}
|
102
|
-
plugin_info_dict = {plugin_info_dict!r}
|
103
100
|
module_fqn = {module_fqn!r}
|
104
101
|
modlib_path = {modlib_path!r}
|
105
102
|
|
@@ -110,19 +107,15 @@ if __name__ == '__main__':
|
|
110
107
|
_ansiballz.run_module(
|
111
108
|
json_params=json_params,
|
112
109
|
profile=profile,
|
113
|
-
plugin_info_dict=plugin_info_dict,
|
114
110
|
module_fqn=module_fqn,
|
115
111
|
modlib_path=modlib_path,
|
116
112
|
init_globals=dict(_respawned=True),
|
117
113
|
)
|
118
114
|
"""
|
119
115
|
|
120
|
-
plugin_info = _plugin_exec_context.PluginExecContext.get_current_plugin_info()
|
121
|
-
|
122
116
|
respawn_code = respawn_code_template.format(
|
123
117
|
json_params=basic._ANSIBLE_ARGS,
|
124
118
|
profile=basic._ANSIBLE_PROFILE,
|
125
|
-
plugin_info_dict=dataclasses.asdict(plugin_info),
|
126
119
|
module_fqn=module_fqn,
|
127
120
|
modlib_path=modlib_path,
|
128
121
|
)
|
@@ -4,15 +4,12 @@
|
|
4
4
|
|
5
5
|
from __future__ import annotations as _annotations
|
6
6
|
|
7
|
-
import datetime as _datetime
|
8
7
|
import typing as _t
|
9
8
|
|
10
|
-
from ansible.module_utils._internal import _traceback,
|
9
|
+
from ansible.module_utils._internal import _traceback, _deprecator
|
11
10
|
from ansible.module_utils.common import messages as _messages
|
12
11
|
from ansible.module_utils import _internal
|
13
12
|
|
14
|
-
_UNSET = _t.cast(_t.Any, ...)
|
15
|
-
|
16
13
|
|
17
14
|
def warn(warning: str) -> None:
|
18
15
|
"""Record a warning to be returned with the module result."""
|
@@ -28,22 +25,23 @@ def warn(warning: str) -> None:
|
|
28
25
|
def deprecate(
|
29
26
|
msg: str,
|
30
27
|
version: str | None = None,
|
31
|
-
date: str |
|
32
|
-
collection_name: str | None =
|
28
|
+
date: str | None = None,
|
29
|
+
collection_name: str | None = None,
|
33
30
|
*,
|
31
|
+
deprecator: _messages.PluginInfo | None = None,
|
34
32
|
help_text: str | None = None,
|
35
33
|
obj: object | None = None,
|
36
34
|
) -> None:
|
37
35
|
"""
|
38
|
-
Record a deprecation warning
|
36
|
+
Record a deprecation warning.
|
39
37
|
The `obj` argument is only useful in a controller context; it is ignored for target-side callers.
|
38
|
+
Most callers do not need to provide `collection_name` or `deprecator` -- but provide only one if needed.
|
39
|
+
Specify `version` or `date`, but not both.
|
40
|
+
If `date` is a string, it must be in the form `YYYY-MM-DD`.
|
40
41
|
"""
|
41
|
-
|
42
|
-
date = str(date)
|
42
|
+
_skip_stackwalk = True
|
43
43
|
|
44
|
-
|
45
|
-
# if collection_name is not _UNSET:
|
46
|
-
# deprecate('The `collection_name` argument to `deprecate` is deprecated.', version='2.27')
|
44
|
+
deprecator = _deprecator.get_best_deprecator(deprecator=deprecator, collection_name=collection_name)
|
47
45
|
|
48
46
|
if _internal.is_controller:
|
49
47
|
_display = _internal.import_controller_module('ansible.utils.display').Display()
|
@@ -53,6 +51,8 @@ def deprecate(
|
|
53
51
|
date=date,
|
54
52
|
help_text=help_text,
|
55
53
|
obj=obj,
|
54
|
+
# skip passing collection_name; get_best_deprecator already accounted for it when present
|
55
|
+
deprecator=deprecator,
|
56
56
|
)
|
57
57
|
|
58
58
|
return
|
@@ -64,7 +64,7 @@ def deprecate(
|
|
64
64
|
formatted_traceback=_traceback.maybe_capture_traceback(_traceback.TracebackEvent.DEPRECATED),
|
65
65
|
version=version,
|
66
66
|
date=date,
|
67
|
-
|
67
|
+
deprecator=deprecator,
|
68
68
|
)] = None
|
69
69
|
|
70
70
|
|
ansible/module_utils/datatag.py
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
"""Public API for data tagging."""
|
2
2
|
from __future__ import annotations as _annotations
|
3
3
|
|
4
|
-
import datetime as _datetime
|
5
4
|
import typing as _t
|
6
5
|
|
7
|
-
from ._internal import
|
6
|
+
from ._internal import _datatag, _deprecator
|
8
7
|
from ._internal._datatag import _tags
|
8
|
+
from .common import messages as _messages
|
9
9
|
|
10
10
|
_T = _t.TypeVar('_T')
|
11
11
|
|
@@ -14,28 +14,28 @@ def deprecate_value(
|
|
14
14
|
value: _T,
|
15
15
|
msg: str,
|
16
16
|
*,
|
17
|
+
version: str | None = None,
|
18
|
+
date: str | None = None,
|
19
|
+
collection_name: str | None = None,
|
20
|
+
deprecator: _messages.PluginInfo | None = None,
|
17
21
|
help_text: str | None = None,
|
18
|
-
removal_date: str | _datetime.date | None = None,
|
19
|
-
removal_version: str | None = None,
|
20
22
|
) -> _T:
|
21
23
|
"""
|
22
24
|
Return `value` tagged with the given deprecation details.
|
23
25
|
The types `None` and `bool` cannot be deprecated and are returned unmodified.
|
24
26
|
Raises a `TypeError` if `value` is not a supported type.
|
25
|
-
|
26
|
-
|
27
|
+
Most callers do not need to provide `collection_name` or `deprecator` -- but provide only one if needed.
|
28
|
+
Specify `version` or `date`, but not both.
|
29
|
+
If `date` is provided, it should be in the form `YYYY-MM-DD`.
|
27
30
|
"""
|
28
|
-
|
29
|
-
# The `fromisoformat` method accepts other ISO 8601 formats than `YYYY-MM-DD` starting with Python 3.11.
|
30
|
-
# That should be considered undocumented behavior of `deprecate_value` rather than an intentional feature.
|
31
|
-
removal_date = _datetime.date.fromisoformat(removal_date)
|
31
|
+
_skip_stackwalk = True
|
32
32
|
|
33
33
|
deprecated = _tags.Deprecated(
|
34
34
|
msg=msg,
|
35
35
|
help_text=help_text,
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
date=date,
|
37
|
+
version=version,
|
38
|
+
deprecator=_deprecator.get_best_deprecator(deprecator=deprecator, collection_name=collection_name),
|
39
39
|
)
|
40
40
|
|
41
41
|
return deprecated.tag(value)
|
ansible/modules/async_status.py
CHANGED
ansible/modules/dnf5.py
CHANGED
@@ -797,7 +797,7 @@ class Dnf5Module(YumDnf):
|
|
797
797
|
if self.module.check_mode:
|
798
798
|
if results:
|
799
799
|
msg = "Check mode: No changes made, but would have if not in check mode"
|
800
|
-
|
800
|
+
elif changed:
|
801
801
|
transaction.download()
|
802
802
|
if not self.download_only:
|
803
803
|
transaction.set_description("ansible dnf5 module")
|
ansible/modules/get_url.py
CHANGED
@@ -87,7 +87,7 @@ options:
|
|
87
87
|
- 'If a checksum is passed to this parameter, the digest of the
|
88
88
|
destination file will be calculated after it is downloaded to ensure
|
89
89
|
its integrity and verify that the transfer completed successfully.
|
90
|
-
Format: <algorithm>:<checksum|url>, for example C(checksum="sha256:D98291AC[...]B6DC7B97",
|
90
|
+
Format: <algorithm>:<checksum|url>, for example C(checksum="sha256:D98291AC[...]B6DC7B97"),
|
91
91
|
C(checksum="sha256:http://example.com/path/sha256sum.txt").'
|
92
92
|
- If you worry about portability, only the sha1 algorithm is available
|
93
93
|
on all platforms and python versions.
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
|
2
|
+
#
|
3
|
+
# This file is part of Ansible
|
4
|
+
#
|
5
|
+
# Ansible is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# Ansible is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
from __future__ import annotations
|
19
|
+
|
20
|
+
import json
|
21
|
+
|
22
|
+
from ansible.utils.display import Display
|
23
|
+
|
24
|
+
Display().deprecated(f'{__name__!r} is deprecated.', version='2.23', help_text='Call `json.dumps` directly instead.')
|
25
|
+
|
26
|
+
|
27
|
+
def jsonify(result, format=False):
|
28
|
+
"""Format JSON output."""
|
29
|
+
|
30
|
+
if result is None:
|
31
|
+
return "{}"
|
32
|
+
|
33
|
+
indent = None
|
34
|
+
if format:
|
35
|
+
indent = 4
|
36
|
+
|
37
|
+
try:
|
38
|
+
return json.dumps(result, sort_keys=True, indent=indent, ensure_ascii=False)
|
39
|
+
except UnicodeDecodeError:
|
40
|
+
return json.dumps(result, sort_keys=True, indent=indent)
|
ansible/parsing/yaml/objects.py
CHANGED
@@ -8,25 +8,36 @@ from ansible.module_utils._internal import _datatag
|
|
8
8
|
from ansible.module_utils.common.text import converters as _converters
|
9
9
|
from ansible.parsing import vault as _vault
|
10
10
|
|
11
|
+
_UNSET = _t.cast(_t.Any, object())
|
12
|
+
|
11
13
|
|
12
14
|
class _AnsibleMapping(dict):
|
13
15
|
"""Backwards compatibility type."""
|
14
16
|
|
15
|
-
def __new__(cls, value):
|
16
|
-
|
17
|
+
def __new__(cls, value=_UNSET, /, **kwargs):
|
18
|
+
if value is _UNSET:
|
19
|
+
return dict(**kwargs)
|
20
|
+
|
21
|
+
return _datatag.AnsibleTagHelper.tag_copy(value, dict(value, **kwargs))
|
17
22
|
|
18
23
|
|
19
24
|
class _AnsibleUnicode(str):
|
20
25
|
"""Backwards compatibility type."""
|
21
26
|
|
22
|
-
def __new__(cls,
|
23
|
-
|
27
|
+
def __new__(cls, object=_UNSET, **kwargs):
|
28
|
+
if object is _UNSET:
|
29
|
+
return str(**kwargs)
|
30
|
+
|
31
|
+
return _datatag.AnsibleTagHelper.tag_copy(object, str(object, **kwargs))
|
24
32
|
|
25
33
|
|
26
34
|
class _AnsibleSequence(list):
|
27
35
|
"""Backwards compatibility type."""
|
28
36
|
|
29
|
-
def __new__(cls, value):
|
37
|
+
def __new__(cls, value=_UNSET, /):
|
38
|
+
if value is _UNSET:
|
39
|
+
return list()
|
40
|
+
|
30
41
|
return _datatag.AnsibleTagHelper.tag_copy(value, list(value))
|
31
42
|
|
32
43
|
|
@@ -21,34 +21,42 @@ import os
|
|
21
21
|
|
22
22
|
from ansible import constants as C
|
23
23
|
from ansible.errors import AnsibleError
|
24
|
+
from ansible.executor.task_result import _RawTaskResult
|
25
|
+
from ansible.inventory.host import Host
|
24
26
|
from ansible.module_utils.common.text.converters import to_text
|
27
|
+
from ansible.parsing.dataloader import DataLoader
|
25
28
|
from ansible.playbook.handler import Handler
|
26
29
|
from ansible.playbook.task_include import TaskInclude
|
27
30
|
from ansible.playbook.role_include import IncludeRole
|
28
31
|
from ansible._internal._templating._engine import TemplateEngine
|
29
32
|
from ansible.utils.display import Display
|
33
|
+
from ansible.vars.manager import VariableManager
|
30
34
|
|
31
35
|
display = Display()
|
32
36
|
|
33
37
|
|
34
38
|
class IncludedFile:
|
35
39
|
|
36
|
-
def __init__(self, filename, args, vars, task, is_role=False):
|
40
|
+
def __init__(self, filename, args, vars, task, is_role: bool = False) -> None:
|
37
41
|
self._filename = filename
|
38
42
|
self._args = args
|
39
43
|
self._vars = vars
|
40
44
|
self._task = task
|
41
|
-
self._hosts = []
|
45
|
+
self._hosts: list[Host] = []
|
42
46
|
self._is_role = is_role
|
43
|
-
self._results = []
|
47
|
+
self._results: list[_RawTaskResult] = []
|
44
48
|
|
45
|
-
def add_host(self, host):
|
49
|
+
def add_host(self, host: Host) -> None:
|
46
50
|
if host not in self._hosts:
|
47
51
|
self._hosts.append(host)
|
48
52
|
return
|
53
|
+
|
49
54
|
raise ValueError()
|
50
55
|
|
51
56
|
def __eq__(self, other):
|
57
|
+
if not isinstance(other, IncludedFile):
|
58
|
+
return False
|
59
|
+
|
52
60
|
return (other._filename == self._filename and
|
53
61
|
other._args == self._args and
|
54
62
|
other._vars == self._vars and
|
@@ -59,23 +67,28 @@ class IncludedFile:
|
|
59
67
|
return "%s (args=%s vars=%s): %s" % (self._filename, self._args, self._vars, self._hosts)
|
60
68
|
|
61
69
|
@staticmethod
|
62
|
-
def process_include_results(
|
63
|
-
|
64
|
-
|
70
|
+
def process_include_results(
|
71
|
+
results: list[_RawTaskResult],
|
72
|
+
iterator,
|
73
|
+
loader: DataLoader,
|
74
|
+
variable_manager: VariableManager,
|
75
|
+
) -> list[IncludedFile]:
|
76
|
+
included_files: list[IncludedFile] = []
|
77
|
+
task_vars_cache: dict[tuple, dict] = {}
|
65
78
|
|
66
79
|
for res in results:
|
67
80
|
|
68
|
-
original_host = res.
|
69
|
-
original_task = res.
|
81
|
+
original_host = res.host
|
82
|
+
original_task = res.task
|
70
83
|
|
71
84
|
if original_task.action in C._ACTION_ALL_INCLUDES:
|
72
85
|
|
73
86
|
if original_task.loop:
|
74
|
-
if 'results' not in res.
|
87
|
+
if 'results' not in res._return_data:
|
75
88
|
continue
|
76
|
-
include_results = res.
|
89
|
+
include_results = res._loop_results
|
77
90
|
else:
|
78
|
-
include_results = [res.
|
91
|
+
include_results = [res._return_data]
|
79
92
|
|
80
93
|
for include_result in include_results:
|
81
94
|
# if the task result was skipped or failed, continue
|