ansible-core 2.19.0b2__py3-none-any.whl → 2.19.0b4__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/__init__.py +1 -1
- ansible/_internal/_ansiballz.py +1 -4
- ansible/_internal/_json/__init__.py +1 -1
- ansible/_internal/_templating/_datatag.py +3 -4
- ansible/_internal/_templating/_engine.py +6 -1
- ansible/_internal/_templating/_jinja_plugins.py +2 -6
- ansible/_internal/_testing.py +26 -0
- ansible/cli/__init__.py +3 -2
- ansible/cli/arguments/option_helpers.py +10 -3
- ansible/cli/doc.py +0 -1
- ansible/config/base.yml +5 -23
- ansible/config/manager.py +144 -103
- ansible/constants.py +1 -63
- ansible/errors/__init__.py +6 -2
- ansible/executor/module_common.py +11 -7
- ansible/executor/task_executor.py +6 -8
- ansible/galaxy/api.py +1 -1
- ansible/galaxy/collection/__init__.py +3 -3
- ansible/inventory/manager.py +1 -0
- 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 +64 -17
- 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/module_utils/facts/virtual/linux.py +1 -1
- ansible/module_utils/parsing/convert_bool.py +6 -0
- ansible/modules/assemble.py +4 -4
- ansible/modules/async_status.py +1 -1
- ansible/modules/cron.py +3 -5
- ansible/modules/dnf5.py +2 -1
- ansible/modules/get_url.py +1 -1
- ansible/modules/git.py +1 -6
- ansible/modules/pip.py +2 -4
- ansible/modules/sysvinit.py +3 -3
- ansible/playbook/task.py +0 -2
- ansible/plugins/__init__.py +18 -8
- ansible/plugins/action/__init__.py +7 -15
- ansible/plugins/action/gather_facts.py +2 -4
- ansible/plugins/action/template.py +3 -0
- ansible/plugins/callback/oneline.py +7 -1
- ansible/plugins/callback/tree.py +7 -1
- 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 +4 -1
- ansible/plugins/inventory/__init__.py +2 -2
- ansible/plugins/loader.py +197 -132
- ansible/plugins/lookup/url.py +2 -2
- ansible/plugins/strategy/__init__.py +6 -6
- ansible/release.py +1 -1
- ansible/template/__init__.py +1 -1
- ansible/utils/collection_loader/__init__.py +2 -0
- ansible/utils/collection_loader/_collection_meta.py +5 -3
- ansible/utils/display.py +137 -71
- ansible/utils/plugin_docs.py +2 -1
- ansible/utils/py3compat.py +1 -7
- ansible/utils/ssh_functions.py +4 -1
- ansible/vars/manager.py +18 -10
- ansible/vars/plugins.py +4 -4
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info}/METADATA +3 -2
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info}/RECORD +82 -79
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info}/WHEEL +1 -1
- 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 +486 -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.0b2.dist-info → ansible_core-2.19.0b4.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info/licenses}/COPYING +0 -0
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info/licenses/licenses}/Apache-License.txt +0 -0
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info/licenses/licenses}/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info/licenses/licenses}/MIT-license.txt +0 -0
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info/licenses/licenses}/PSF-license.txt +0 -0
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info/licenses/licenses}/simplified_bsd.txt +0 -0
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info}/top_level.txt +0 -0
@@ -822,12 +822,12 @@ class StrategyBase:
|
|
822
822
|
"""
|
823
823
|
if handle_stats_and_callbacks:
|
824
824
|
display.deprecated(
|
825
|
-
"Reporting play recap stats and running callbacks functionality for "
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
version="2.21"
|
825
|
+
msg="Reporting play recap stats and running callbacks functionality for "
|
826
|
+
"``include_tasks`` in ``StrategyBase._load_included_file`` is deprecated. "
|
827
|
+
"See ``https://github.com/ansible/ansible/pull/79260`` for guidance on how to "
|
828
|
+
"move the reporting into specific strategy plugins to account for "
|
829
|
+
"``include_role`` tasks as well.",
|
830
|
+
version="2.21",
|
831
831
|
)
|
832
832
|
display.debug("loading included file: %s" % included_file._filename)
|
833
833
|
try:
|
ansible/release.py
CHANGED
ansible/template/__init__.py
CHANGED
@@ -388,7 +388,7 @@ def generate_ansible_template_vars(path: str, fullpath: str | None = None, dest_
|
|
388
388
|
value=ansible_managed,
|
389
389
|
msg="The `ansible_managed` variable is deprecated.",
|
390
390
|
help_text="Define and use a custom variable instead.",
|
391
|
-
|
391
|
+
version='2.23',
|
392
392
|
)
|
393
393
|
|
394
394
|
temp_vars = dict(
|
@@ -13,6 +13,8 @@ import typing as t
|
|
13
13
|
class _EncryptedStringProtocol(t.Protocol):
|
14
14
|
"""Protocol representing an `EncryptedString`, since it cannot be imported here."""
|
15
15
|
|
16
|
+
# DTFIX-FUTURE: collapse this with the one in config, once we can
|
17
|
+
|
16
18
|
def _decrypt(self) -> str: ...
|
17
19
|
|
18
20
|
|
@@ -24,11 +24,13 @@ def _meta_yml_to_dict(yaml_string_data: bytes | str, content_id):
|
|
24
24
|
import yaml
|
25
25
|
|
26
26
|
try:
|
27
|
-
from yaml import
|
27
|
+
from yaml import CBaseLoader as BaseLoader
|
28
28
|
except (ImportError, AttributeError):
|
29
|
-
from yaml import
|
29
|
+
from yaml import BaseLoader # type: ignore[assignment]
|
30
30
|
|
31
|
-
|
31
|
+
# Using BaseLoader ensures that all scalars are strings.
|
32
|
+
# Doing so avoids parsing unquoted versions as floats, dates as datetime.date, etc.
|
33
|
+
routing_dict = yaml.load(yaml_string_data, Loader=BaseLoader)
|
32
34
|
if not routing_dict:
|
33
35
|
routing_dict = {}
|
34
36
|
if not isinstance(routing_dict, Mapping):
|
ansible/utils/display.py
CHANGED
@@ -18,7 +18,6 @@
|
|
18
18
|
from __future__ import annotations
|
19
19
|
|
20
20
|
import dataclasses
|
21
|
-
import datetime
|
22
21
|
|
23
22
|
try:
|
24
23
|
import curses
|
@@ -50,9 +49,10 @@ from functools import wraps
|
|
50
49
|
from struct import unpack, pack
|
51
50
|
|
52
51
|
from ansible import constants as C
|
52
|
+
from ansible.constants import config
|
53
53
|
from ansible.errors import AnsibleAssertionError, AnsiblePromptInterrupt, AnsiblePromptNoninteractive, AnsibleError
|
54
54
|
from ansible._internal._errors import _utils
|
55
|
-
from ansible.module_utils._internal import _ambient_context,
|
55
|
+
from ansible.module_utils._internal import _ambient_context, _deprecator
|
56
56
|
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
57
57
|
from ansible._internal._datatag._tags import TrustedAsTemplate
|
58
58
|
from ansible.module_utils.common.messages import ErrorSummary, WarningSummary, DeprecationSummary, Detail, SummaryBase, PluginInfo
|
@@ -76,8 +76,6 @@ _LIBC.wcswidth.argtypes = (ctypes.c_wchar_p, ctypes.c_int)
|
|
76
76
|
# Max for c_int
|
77
77
|
_MAX_INT = 2 ** (ctypes.sizeof(ctypes.c_int) * 8 - 1) - 1
|
78
78
|
|
79
|
-
_UNSET = t.cast(t.Any, object())
|
80
|
-
|
81
79
|
MOVE_TO_BOL = b'\r'
|
82
80
|
CLEAR_TO_EOL = b'\x1b[K'
|
83
81
|
|
@@ -555,7 +553,7 @@ class Display(metaclass=Singleton):
|
|
555
553
|
msg: str,
|
556
554
|
version: str | None = None,
|
557
555
|
removed: bool = False,
|
558
|
-
date: str |
|
556
|
+
date: str | None = None,
|
559
557
|
collection_name: str | None = None,
|
560
558
|
) -> str:
|
561
559
|
"""Return a deprecation message and help text for non-display purposes (e.g., exception messages)."""
|
@@ -570,7 +568,7 @@ class Display(metaclass=Singleton):
|
|
570
568
|
version=version,
|
571
569
|
removed=removed,
|
572
570
|
date=date,
|
573
|
-
|
571
|
+
deprecator=PluginInfo._from_collection_name(collection_name),
|
574
572
|
)
|
575
573
|
|
576
574
|
if removed:
|
@@ -582,57 +580,63 @@ class Display(metaclass=Singleton):
|
|
582
580
|
|
583
581
|
def _get_deprecation_message_with_plugin_info(
|
584
582
|
self,
|
583
|
+
*,
|
585
584
|
msg: str,
|
586
|
-
version: str | None
|
585
|
+
version: str | None,
|
587
586
|
removed: bool = False,
|
588
|
-
date: str |
|
589
|
-
|
587
|
+
date: str | None,
|
588
|
+
deprecator: PluginInfo | None,
|
590
589
|
) -> str:
|
591
590
|
"""Internal use only. Return a deprecation message and help text for display."""
|
592
|
-
|
593
|
-
|
594
|
-
if msg and msg[-1] not in ['!', '?', '.']:
|
595
|
-
msg += '.'
|
591
|
+
# DTFIX-RELEASE: the logic for omitting date/version doesn't apply to the payload, so it shows up in vars in some cases when it should not
|
596
592
|
|
597
593
|
if removed:
|
598
594
|
removal_fragment = 'This feature was removed'
|
599
|
-
help_text = 'Please update your playbooks.'
|
600
595
|
else:
|
601
596
|
removal_fragment = 'This feature will be removed'
|
602
|
-
help_text = ''
|
603
597
|
|
604
|
-
if
|
605
|
-
|
598
|
+
if not deprecator or deprecator.type == _deprecator.INDETERMINATE_DEPRECATOR.type:
|
599
|
+
collection = None
|
600
|
+
plugin_fragment = ''
|
601
|
+
elif deprecator.type == _deprecator.PluginInfo._COLLECTION_ONLY_TYPE:
|
602
|
+
collection = deprecator.resolved_name
|
603
|
+
plugin_fragment = ''
|
606
604
|
else:
|
607
|
-
|
605
|
+
parts = deprecator.resolved_name.split('.')
|
606
|
+
plugin_name = parts[-1]
|
607
|
+
# DTFIX-RELEASE: normalize 'modules' -> 'module' before storing it so we can eliminate the normalization here
|
608
|
+
plugin_type = "module" if deprecator.type in ("module", "modules") else f'{deprecator.type} plugin'
|
608
609
|
|
609
|
-
|
610
|
-
|
611
|
-
elif version:
|
612
|
-
when = 'in version {0}.'.format(version)
|
613
|
-
else:
|
614
|
-
when = 'in a future release.'
|
610
|
+
collection = '.'.join(parts[:2]) if len(parts) > 2 else None
|
611
|
+
plugin_fragment = f'{plugin_type} {plugin_name!r}'
|
615
612
|
|
616
|
-
|
613
|
+
if collection and plugin_fragment:
|
614
|
+
plugin_fragment += ' in'
|
617
615
|
|
618
|
-
|
616
|
+
if collection == 'ansible.builtin':
|
617
|
+
collection_fragment = 'ansible-core'
|
618
|
+
elif collection:
|
619
|
+
collection_fragment = f'collection {collection!r}'
|
620
|
+
else:
|
621
|
+
collection_fragment = ''
|
619
622
|
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
if plugin_info.type in ("module", "modules"):
|
627
|
-
# DTFIX-RELEASE: pluginloader or AnsiblePlugin needs a "type desc" property that doesn't suffer from legacy "inconsistencies" like this
|
628
|
-
plugin_type = "module"
|
629
|
-
elif plugin_info.type == "collection":
|
630
|
-
# not a real plugin type, but used for tombstone errors generated by plugin loader
|
631
|
-
plugin_type = plugin_info.type
|
623
|
+
if not collection:
|
624
|
+
when_fragment = 'in the future' if not removed else ''
|
625
|
+
elif date:
|
626
|
+
when_fragment = f'in a release after {date}'
|
627
|
+
elif version:
|
628
|
+
when_fragment = f'version {version}'
|
632
629
|
else:
|
633
|
-
|
630
|
+
when_fragment = 'in a future release' if not removed else ''
|
634
631
|
|
635
|
-
|
632
|
+
if plugin_fragment or collection_fragment:
|
633
|
+
from_fragment = 'from'
|
634
|
+
else:
|
635
|
+
from_fragment = ''
|
636
|
+
|
637
|
+
deprecation_msg = ' '.join(f for f in [removal_fragment, from_fragment, plugin_fragment, collection_fragment, when_fragment] if f) + '.'
|
638
|
+
|
639
|
+
return _join_sentences(msg, deprecation_msg)
|
636
640
|
|
637
641
|
def _wrap_message(self, msg: str, wrap_text: bool) -> str:
|
638
642
|
if wrap_text and self._wrap_stderr:
|
@@ -661,20 +665,24 @@ class Display(metaclass=Singleton):
|
|
661
665
|
msg: str,
|
662
666
|
version: str | None = None,
|
663
667
|
removed: bool = False,
|
664
|
-
date: str |
|
665
|
-
collection_name: str | None =
|
668
|
+
date: str | None = None,
|
669
|
+
collection_name: str | None = None,
|
666
670
|
*,
|
671
|
+
deprecator: PluginInfo | None = None,
|
667
672
|
help_text: str | None = None,
|
668
673
|
obj: t.Any = None,
|
669
674
|
) -> None:
|
670
|
-
"""
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
+
"""
|
676
|
+
Display a deprecation warning message, if enabled.
|
677
|
+
Most callers do not need to provide `collection_name` or `deprecator` -- but provide only one if needed.
|
678
|
+
Specify `version` or `date`, but not both.
|
679
|
+
If `date` is a string, it must be in the form `YYYY-MM-DD`.
|
680
|
+
"""
|
675
681
|
# DTFIX-RELEASE: are there any deprecation calls where the feature is switching from enabled to disabled, rather than being removed entirely?
|
676
682
|
# DTFIX-RELEASE: are there deprecated features which should going through deferred deprecation instead?
|
677
683
|
|
684
|
+
_skip_stackwalk = True
|
685
|
+
|
678
686
|
self._deprecated_with_plugin_info(
|
679
687
|
msg=msg,
|
680
688
|
version=version,
|
@@ -682,32 +690,36 @@ class Display(metaclass=Singleton):
|
|
682
690
|
date=date,
|
683
691
|
help_text=help_text,
|
684
692
|
obj=obj,
|
685
|
-
|
693
|
+
deprecator=_deprecator.get_best_deprecator(deprecator=deprecator, collection_name=collection_name),
|
686
694
|
)
|
687
695
|
|
688
696
|
def _deprecated_with_plugin_info(
|
689
697
|
self,
|
698
|
+
*,
|
690
699
|
msg: str,
|
691
|
-
version: str | None
|
700
|
+
version: str | None,
|
692
701
|
removed: bool = False,
|
693
|
-
date: str |
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
plugin: PluginInfo | None = None,
|
702
|
+
date: str | None,
|
703
|
+
help_text: str | None,
|
704
|
+
obj: t.Any,
|
705
|
+
deprecator: PluginInfo | None,
|
698
706
|
) -> None:
|
699
707
|
"""
|
700
708
|
This is the internal pre-proxy half of the `deprecated` implementation.
|
701
709
|
Any logic that must occur on workers needs to be implemented here.
|
702
710
|
"""
|
711
|
+
_skip_stackwalk = True
|
712
|
+
|
703
713
|
if removed:
|
704
|
-
|
714
|
+
formatted_msg = self._get_deprecation_message_with_plugin_info(
|
705
715
|
msg=msg,
|
706
716
|
version=version,
|
707
717
|
removed=removed,
|
708
718
|
date=date,
|
709
|
-
|
710
|
-
)
|
719
|
+
deprecator=deprecator,
|
720
|
+
)
|
721
|
+
|
722
|
+
raise AnsibleError(formatted_msg)
|
711
723
|
|
712
724
|
if source_context := _utils.SourceContext.from_value(obj):
|
713
725
|
formatted_source_context = str(source_context)
|
@@ -723,8 +735,8 @@ class Display(metaclass=Singleton):
|
|
723
735
|
),
|
724
736
|
),
|
725
737
|
version=version,
|
726
|
-
date=
|
727
|
-
|
738
|
+
date=date,
|
739
|
+
deprecator=deprecator,
|
728
740
|
formatted_traceback=_traceback.maybe_capture_traceback(_traceback.TracebackEvent.DEPRECATED),
|
729
741
|
)
|
730
742
|
|
@@ -1225,20 +1237,74 @@ def _get_message_lines(message: str, help_text: str | None, formatted_source_con
|
|
1225
1237
|
return message_lines
|
1226
1238
|
|
1227
1239
|
|
1240
|
+
def _join_sentences(first: str | None, second: str | None) -> str:
|
1241
|
+
"""Join two sentences together."""
|
1242
|
+
first = (first or '').strip()
|
1243
|
+
second = (second or '').strip()
|
1244
|
+
|
1245
|
+
if first and first[-1] not in ('!', '?', '.'):
|
1246
|
+
first += '.'
|
1247
|
+
|
1248
|
+
if second and second[-1] not in ('!', '?', '.'):
|
1249
|
+
second += '.'
|
1250
|
+
|
1251
|
+
if first and not second:
|
1252
|
+
return first
|
1253
|
+
|
1254
|
+
if not first and second:
|
1255
|
+
return second
|
1256
|
+
|
1257
|
+
return ' '.join((first, second))
|
1258
|
+
|
1259
|
+
|
1228
1260
|
def format_message(summary: SummaryBase) -> str:
|
1229
|
-
details:
|
1261
|
+
details: c.Sequence[Detail] = summary.details
|
1262
|
+
|
1263
|
+
if isinstance(summary, DeprecationSummary) and details:
|
1264
|
+
# augment the first detail element for deprecations to include additional diagnostic info and help text
|
1265
|
+
detail_list = list(details)
|
1266
|
+
detail = detail_list[0]
|
1267
|
+
|
1268
|
+
deprecation_msg = _display._get_deprecation_message_with_plugin_info(
|
1269
|
+
msg=detail.msg,
|
1270
|
+
version=summary.version,
|
1271
|
+
date=summary.date,
|
1272
|
+
deprecator=summary.deprecator,
|
1273
|
+
)
|
1230
1274
|
|
1231
|
-
|
1232
|
-
details = [detail if idx else dataclasses.replace(
|
1275
|
+
detail_list[0] = dataclasses.replace(
|
1233
1276
|
detail,
|
1234
|
-
msg=
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
),
|
1240
|
-
) for idx, detail in enumerate(summary.details)]
|
1241
|
-
else:
|
1242
|
-
details = summary.details
|
1277
|
+
msg=deprecation_msg,
|
1278
|
+
help_text=detail.help_text,
|
1279
|
+
)
|
1280
|
+
|
1281
|
+
details = detail_list
|
1243
1282
|
|
1244
1283
|
return _format_error_details(details, summary.formatted_traceback)
|
1284
|
+
|
1285
|
+
|
1286
|
+
def _report_config_warnings(deprecator: PluginInfo) -> None:
|
1287
|
+
"""Called by config to report warnings/deprecations collected during a config parse."""
|
1288
|
+
while config._errors:
|
1289
|
+
msg, exception = config._errors.pop()
|
1290
|
+
_display.error_as_warning(msg=msg, exception=exception)
|
1291
|
+
|
1292
|
+
while config.WARNINGS:
|
1293
|
+
warn = config.WARNINGS.pop()
|
1294
|
+
_display.warning(warn)
|
1295
|
+
|
1296
|
+
while config.DEPRECATED:
|
1297
|
+
# tuple with name and options
|
1298
|
+
dep = config.DEPRECATED.pop(0)
|
1299
|
+
msg = config.get_deprecated_msg_from_config(dep[1]).replace("\t", "")
|
1300
|
+
|
1301
|
+
_display.deprecated( # pylint: disable=ansible-deprecated-unnecessary-collection-name,ansible-invalid-deprecated-version
|
1302
|
+
msg=f"{dep[0]} option. {msg}",
|
1303
|
+
version=dep[1]['version'],
|
1304
|
+
deprecator=deprecator,
|
1305
|
+
)
|
1306
|
+
|
1307
|
+
|
1308
|
+
# emit any warnings or deprecations
|
1309
|
+
# in the event config fails before display is up, we'll lose warnings -- but that's OK, since everything is broken anyway
|
1310
|
+
_report_config_warnings(_deprecator.ANSIBLE_CORE_DEPRECATOR)
|
ansible/utils/plugin_docs.py
CHANGED
@@ -154,7 +154,8 @@ def add_fragments(doc, filename, fragment_loader, is_module=False):
|
|
154
154
|
unknown_fragments.append(fragment_slug)
|
155
155
|
continue
|
156
156
|
|
157
|
-
|
157
|
+
# trust-tagged source propagates to loaded values; expressions and templates in config require trust
|
158
|
+
fragment_yaml = _tags.TrustedAsTemplate().tag(getattr(fragment_class, fragment_var, None))
|
158
159
|
if fragment_yaml is None:
|
159
160
|
if fragment_var != 'DOCUMENTATION':
|
160
161
|
# if it's asking for something specific that's missing, that's an error
|
ansible/utils/py3compat.py
CHANGED
@@ -6,7 +6,6 @@
|
|
6
6
|
|
7
7
|
from __future__ import annotations
|
8
8
|
|
9
|
-
import inspect
|
10
9
|
import os
|
11
10
|
|
12
11
|
from ansible.utils.display import Display
|
@@ -19,13 +18,8 @@ def __getattr__(name):
|
|
19
18
|
if name != 'environ':
|
20
19
|
raise AttributeError(name)
|
21
20
|
|
22
|
-
caller = inspect.stack()[1]
|
23
|
-
|
24
21
|
display.deprecated(
|
25
|
-
|
26
|
-
'ansible.utils.py3compat.environ is deprecated in favor of os.environ. '
|
27
|
-
f'Accessed by {caller.filename} line number {caller.lineno}'
|
28
|
-
),
|
22
|
+
msg='ansible.utils.py3compat.environ is deprecated in favor of os.environ.',
|
29
23
|
version='2.20',
|
30
24
|
)
|
31
25
|
|
ansible/utils/ssh_functions.py
CHANGED
@@ -56,7 +56,10 @@ def set_default_transport():
|
|
56
56
|
|
57
57
|
# deal with 'smart' connection .. one time ..
|
58
58
|
if C.DEFAULT_TRANSPORT == 'smart':
|
59
|
-
display.deprecated(
|
59
|
+
display.deprecated(
|
60
|
+
msg="The 'smart' option for connections is deprecated. Set the connection plugin directly instead.",
|
61
|
+
version='2.20',
|
62
|
+
)
|
60
63
|
|
61
64
|
# see if SSH can support ControlPersist if not use paramiko
|
62
65
|
if not check_for_controlpersist('ssh') and paramiko is not None:
|
ansible/vars/manager.py
CHANGED
@@ -25,6 +25,8 @@ from collections import defaultdict
|
|
25
25
|
from collections.abc import Mapping, MutableMapping
|
26
26
|
|
27
27
|
from ansible import constants as C
|
28
|
+
from ansible.module_utils._internal import _deprecator
|
29
|
+
from ansible.module_utils._internal._datatag import _tags
|
28
30
|
from ansible.errors import (AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleFileNotFound,
|
29
31
|
AnsibleAssertionError, AnsibleValueOmittedError)
|
30
32
|
from ansible.inventory.host import Host
|
@@ -32,7 +34,6 @@ from ansible.inventory.helpers import sort_groups, get_group_vars
|
|
32
34
|
from ansible.inventory.manager import InventoryManager
|
33
35
|
from ansible.module_utils.datatag import native_type_name
|
34
36
|
from ansible.module_utils.six import text_type
|
35
|
-
from ansible.module_utils.datatag import deprecate_value
|
36
37
|
from ansible.parsing.dataloader import DataLoader
|
37
38
|
from ansible._internal._templating._engine import TemplateEngine
|
38
39
|
from ansible.plugins.loader import cache_loader
|
@@ -50,8 +51,12 @@ if t.TYPE_CHECKING:
|
|
50
51
|
display = Display()
|
51
52
|
|
52
53
|
# deprecated: description='enable top-level facts deprecation' core_version='2.20'
|
53
|
-
#
|
54
|
-
#
|
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
|
+
# )
|
55
60
|
|
56
61
|
|
57
62
|
def _deprecate_top_level_fact(value: t.Any) -> t.Any:
|
@@ -61,7 +66,7 @@ def _deprecate_top_level_fact(value: t.Any) -> t.Any:
|
|
61
66
|
Unique tag instances are required to achieve the correct de-duplication within a top-level templating operation.
|
62
67
|
"""
|
63
68
|
# deprecated: description='enable top-level facts deprecation' core_version='2.20'
|
64
|
-
# return
|
69
|
+
# return _DEPRECATE_TOP_LEVEL_FACT_TAG.tag(value)
|
65
70
|
return value
|
66
71
|
|
67
72
|
|
@@ -96,6 +101,13 @@ class VariableManager:
|
|
96
101
|
_ALLOWED = frozenset(['plugins_by_group', 'groups_plugins_play', 'groups_plugins_inventory', 'groups_inventory',
|
97
102
|
'all_plugins_play', 'all_plugins_inventory', 'all_inventory'])
|
98
103
|
|
104
|
+
_PLAY_HOSTS_DEPRECATED_TAG = _tags.Deprecated(
|
105
|
+
msg='The `play_hosts` magic variable is deprecated.',
|
106
|
+
version='2.23',
|
107
|
+
deprecator=_deprecator.ANSIBLE_CORE_DEPRECATOR,
|
108
|
+
help_text='Use `ansible_play_batch` instead.',
|
109
|
+
)
|
110
|
+
|
99
111
|
def __init__(self, loader: DataLoader | None = None, inventory: InventoryManager | None = None, version_info: dict[str, str] | None = None) -> None:
|
100
112
|
self._nonpersistent_fact_cache: defaultdict[str, dict] = defaultdict(dict)
|
101
113
|
self._vars_cache: defaultdict[str, dict] = defaultdict(dict)
|
@@ -477,12 +489,8 @@ class VariableManager:
|
|
477
489
|
variables['ansible_play_hosts'] = [x for x in variables['ansible_play_hosts_all'] if x not in play._removed_hosts]
|
478
490
|
variables['ansible_play_batch'] = [x for x in _hosts if x not in play._removed_hosts]
|
479
491
|
|
480
|
-
|
481
|
-
|
482
|
-
msg='The `play_hosts` magic variable is deprecated.',
|
483
|
-
removal_version='2.23',
|
484
|
-
help_text='Use `ansible_play_batch` instead.',
|
485
|
-
)
|
492
|
+
# use a static tag instead of `deprecate_value` to avoid stackwalk in a hot code path
|
493
|
+
variables['play_hosts'] = self._PLAY_HOSTS_DEPRECATED_TAG.tag(variables['ansible_play_batch'])
|
486
494
|
|
487
495
|
# Set options vars
|
488
496
|
for option, option_value in self._options_vars.items():
|
ansible/vars/plugins.py
CHANGED
@@ -34,10 +34,10 @@ def get_plugin_vars(loader, plugin, path, entities):
|
|
34
34
|
except AttributeError:
|
35
35
|
if hasattr(plugin, 'get_host_vars') or hasattr(plugin, 'get_group_vars'):
|
36
36
|
display.deprecated(
|
37
|
-
f"The vars plugin {plugin.ansible_name} from {plugin._original_path} is relying "
|
38
|
-
|
39
|
-
|
40
|
-
|
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.",
|
41
41
|
version="2.20",
|
42
42
|
)
|
43
43
|
try:
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: ansible-core
|
3
|
-
Version: 2.19.
|
3
|
+
Version: 2.19.0b4
|
4
4
|
Summary: Radically simple IT automation
|
5
5
|
Author: Ansible Project
|
6
6
|
Project-URL: Homepage, https://ansible.com/
|
@@ -38,6 +38,7 @@ Requires-Dist: PyYAML>=5.1
|
|
38
38
|
Requires-Dist: cryptography
|
39
39
|
Requires-Dist: packaging
|
40
40
|
Requires-Dist: resolvelib<2.0.0,>=0.5.3
|
41
|
+
Dynamic: license-file
|
41
42
|
|
42
43
|
[](https://pypi.org/project/ansible-core)
|
43
44
|
[](https://docs.ansible.com/ansible/latest/)
|