ansible-core 2.19.4rc1__py3-none-any.whl → 2.20.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ansible-core might be problematic. Click here for more details.
- ansible/_internal/__init__.py +1 -4
- ansible/_internal/_ansiballz/_builder.py +1 -3
- ansible/_internal/_collection_proxy.py +7 -9
- ansible/_internal/_json/__init__.py +3 -4
- ansible/_internal/_templating/_engine.py +1 -1
- ansible/_internal/_templating/_jinja_plugins.py +1 -2
- ansible/_internal/_wrapt.py +105 -301
- ansible/cli/__init__.py +11 -10
- ansible/cli/adhoc.py +1 -2
- ansible/cli/arguments/option_helpers.py +1 -1
- ansible/cli/config.py +5 -6
- ansible/cli/doc.py +67 -67
- ansible/cli/galaxy.py +15 -24
- ansible/cli/inventory.py +0 -1
- ansible/cli/playbook.py +0 -1
- ansible/cli/pull.py +0 -1
- ansible/cli/scripts/ansible_connection_cli_stub.py +1 -1
- ansible/config/base.yml +1 -25
- ansible/config/manager.py +0 -2
- ansible/executor/play_iterator.py +42 -20
- ansible/executor/playbook_executor.py +0 -9
- ansible/executor/task_executor.py +26 -18
- ansible/executor/task_queue_manager.py +1 -3
- ansible/galaxy/api.py +33 -80
- ansible/galaxy/collection/__init__.py +11 -21
- ansible/galaxy/dependency_resolution/__init__.py +10 -9
- ansible/galaxy/dependency_resolution/dataclasses.py +86 -70
- ansible/galaxy/dependency_resolution/providers.py +54 -134
- ansible/galaxy/dependency_resolution/versioning.py +2 -4
- ansible/galaxy/role.py +1 -33
- ansible/inventory/manager.py +2 -3
- ansible/keyword_desc.yml +0 -3
- ansible/module_utils/_internal/_datatag/__init__.py +2 -10
- ansible/module_utils/_internal/_no_six.py +86 -0
- ansible/module_utils/_text.py +28 -8
- ansible/module_utils/ansible_release.py +2 -2
- ansible/module_utils/basic.py +26 -23
- ansible/module_utils/common/_collections_compat.py +11 -2
- ansible/module_utils/common/collections.py +8 -3
- ansible/module_utils/common/dict_transformations.py +1 -2
- ansible/module_utils/common/network.py +4 -2
- ansible/module_utils/common/parameters.py +32 -41
- ansible/module_utils/common/text/converters.py +109 -23
- ansible/module_utils/common/text/formatters.py +6 -2
- ansible/module_utils/common/validation.py +11 -9
- ansible/module_utils/connection.py +8 -3
- ansible/module_utils/facts/hardware/linux.py +23 -7
- ansible/module_utils/facts/hardware/netbsd.py +1 -1
- ansible/module_utils/facts/hardware/sunos.py +2 -1
- ansible/module_utils/facts/packages.py +6 -2
- ansible/module_utils/facts/system/distribution.py +2 -1
- ansible/module_utils/facts/system/env.py +6 -3
- ansible/module_utils/facts/system/local.py +3 -1
- ansible/module_utils/parsing/convert_bool.py +6 -2
- ansible/module_utils/service.py +2 -3
- ansible/module_utils/six/__init__.py +11 -6
- ansible/module_utils/yumdnf.py +0 -5
- ansible/modules/apt.py +18 -13
- ansible/modules/apt_repository.py +1 -1
- ansible/modules/assemble.py +5 -9
- ansible/modules/blockinfile.py +39 -23
- ansible/modules/cron.py +26 -35
- ansible/modules/deb822_repository.py +83 -12
- ansible/modules/dnf.py +3 -7
- ansible/modules/dnf5.py +4 -6
- ansible/modules/expect.py +0 -3
- ansible/modules/find.py +1 -2
- ansible/modules/get_url.py +1 -1
- ansible/modules/git.py +4 -5
- ansible/modules/include_vars.py +1 -1
- ansible/modules/known_hosts.py +7 -1
- ansible/modules/lineinfile.py +71 -63
- ansible/modules/package_facts.py +1 -1
- ansible/modules/pip.py +8 -2
- ansible/modules/replace.py +6 -6
- ansible/modules/service.py +3 -4
- ansible/modules/stat.py +20 -0
- ansible/modules/uri.py +9 -10
- ansible/modules/user.py +1 -2
- ansible/modules/wait_for.py +2 -2
- ansible/modules/wait_for_connection.py +2 -1
- ansible/modules/yum_repository.py +1 -16
- ansible/parsing/dataloader.py +24 -31
- ansible/parsing/vault/__init__.py +1 -2
- ansible/playbook/base.py +8 -56
- ansible/playbook/block.py +0 -60
- ansible/playbook/collectionsearch.py +1 -2
- ansible/playbook/handler.py +1 -7
- ansible/playbook/helpers.py +0 -7
- ansible/playbook/included_file.py +1 -1
- ansible/playbook/play.py +102 -36
- ansible/playbook/play_context.py +4 -0
- ansible/playbook/role/__init__.py +10 -65
- ansible/playbook/role/definition.py +3 -4
- ansible/playbook/role/include.py +2 -3
- ansible/playbook/role/metadata.py +1 -12
- ansible/playbook/role/requirement.py +1 -2
- ansible/playbook/role_include.py +1 -2
- ansible/playbook/taggable.py +16 -5
- ansible/playbook/task.py +11 -50
- ansible/plugins/action/__init__.py +20 -19
- ansible/plugins/action/add_host.py +1 -2
- ansible/plugins/action/fetch.py +3 -5
- ansible/plugins/action/group_by.py +1 -2
- ansible/plugins/action/include_vars.py +20 -22
- ansible/plugins/action/script.py +1 -3
- ansible/plugins/action/template.py +1 -2
- ansible/plugins/action/uri.py +4 -2
- ansible/plugins/cache/__init__.py +1 -0
- ansible/plugins/callback/__init__.py +13 -6
- ansible/plugins/connection/__init__.py +3 -7
- ansible/plugins/connection/local.py +2 -3
- ansible/plugins/connection/psrp.py +0 -2
- ansible/plugins/connection/ssh.py +2 -7
- ansible/plugins/connection/winrm.py +0 -2
- ansible/plugins/doc_fragments/result_format_callback.py +15 -0
- ansible/plugins/filter/core.py +4 -5
- ansible/plugins/filter/encryption.py +3 -27
- ansible/plugins/filter/mathstuff.py +1 -2
- ansible/plugins/filter/to_nice_yaml.yml +31 -3
- ansible/plugins/filter/to_yaml.yml +29 -12
- ansible/plugins/inventory/__init__.py +1 -2
- ansible/plugins/inventory/toml.py +3 -6
- ansible/plugins/inventory/yaml.py +1 -2
- ansible/plugins/loader.py +3 -4
- ansible/plugins/lookup/password.py +1 -2
- ansible/plugins/lookup/subelements.py +2 -3
- ansible/plugins/lookup/url.py +1 -1
- ansible/plugins/lookup/varnames.py +1 -2
- ansible/plugins/shell/__init__.py +9 -4
- ansible/plugins/shell/powershell.py +8 -24
- ansible/plugins/strategy/__init__.py +5 -2
- ansible/plugins/test/core.py +4 -1
- ansible/plugins/test/falsy.yml +1 -1
- ansible/plugins/test/regex.yml +18 -6
- ansible/plugins/test/truthy.yml +1 -1
- ansible/release.py +2 -2
- ansible/template/__init__.py +3 -7
- ansible/utils/collection_loader/_collection_config.py +5 -0
- ansible/utils/collection_loader/_collection_finder.py +11 -14
- ansible/utils/context_objects.py +7 -4
- ansible/utils/display.py +7 -6
- ansible/utils/encrypt.py +0 -5
- ansible/utils/helpers.py +6 -2
- ansible/utils/jsonrpc.py +7 -3
- ansible/utils/plugin_docs.py +49 -38
- ansible/utils/ssh_functions.py +0 -19
- ansible/utils/unsafe_proxy.py +7 -7
- ansible/vars/clean.py +2 -3
- ansible/vars/manager.py +28 -22
- ansible/vars/plugins.py +1 -31
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/METADATA +4 -4
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/RECORD +213 -214
- ansible_test/_data/completion/docker.txt +7 -7
- ansible_test/_data/completion/network.txt +0 -1
- ansible_test/_data/completion/remote.txt +4 -4
- ansible_test/_data/requirements/ansible-test.txt +1 -1
- ansible_test/_data/requirements/ansible.txt +1 -1
- ansible_test/_data/requirements/sanity.ansible-doc.txt +2 -2
- ansible_test/_data/requirements/sanity.changelog.txt +2 -2
- ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
- ansible_test/_data/requirements/sanity.import.txt +1 -1
- ansible_test/_data/requirements/sanity.integration-aliases.txt +1 -1
- ansible_test/_data/requirements/sanity.pep8.txt +1 -1
- ansible_test/_data/requirements/sanity.pylint.txt +6 -6
- ansible_test/_data/requirements/sanity.runtime-metadata.txt +1 -1
- ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
- ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
- ansible_test/_internal/cache.py +2 -5
- ansible_test/_internal/cli/compat.py +1 -1
- ansible_test/_internal/commands/coverage/combine.py +1 -3
- ansible_test/_internal/commands/integration/__init__.py +3 -7
- ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
- ansible_test/_internal/commands/integration/coverage.py +1 -3
- ansible_test/_internal/commands/integration/filters.py +5 -10
- ansible_test/_internal/commands/sanity/pylint.py +11 -0
- ansible_test/_internal/commands/sanity/validate_modules.py +1 -5
- ansible_test/_internal/commands/units/__init__.py +1 -13
- ansible_test/_internal/compat/packaging.py +2 -2
- ansible_test/_internal/compat/yaml.py +2 -2
- ansible_test/_internal/completion.py +2 -5
- ansible_test/_internal/config.py +2 -7
- ansible_test/_internal/coverage_util.py +1 -1
- ansible_test/_internal/delegation.py +2 -0
- ansible_test/_internal/docker_util.py +1 -1
- ansible_test/_internal/host_profiles.py +6 -11
- ansible_test/_internal/provider/__init__.py +2 -5
- ansible_test/_internal/provisioning.py +2 -5
- ansible_test/_internal/pypi_proxy.py +1 -1
- ansible_test/_internal/python_requirements.py +1 -1
- ansible_test/_internal/target.py +2 -6
- ansible_test/_internal/thread.py +1 -4
- ansible_test/_internal/util.py +9 -14
- ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +14 -19
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +48 -45
- ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +9 -7
- ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +51 -37
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +31 -18
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +1 -2
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +59 -71
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -2
- ansible_test/_util/target/cli/ansible_test_cli_stub.py +4 -2
- ansible_test/_util/target/common/constants.py +2 -2
- ansible_test/_util/target/setup/bootstrap.sh +0 -6
- ansible/utils/py3compat.py +0 -27
- ansible_test/_data/pytest/config/legacy.ini +0 -4
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/WHEEL +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/top_level.txt +0 -0
|
@@ -52,7 +52,6 @@ import re
|
|
|
52
52
|
|
|
53
53
|
from ansible.errors import AnsibleError
|
|
54
54
|
from ansible.module_utils.common.text.converters import to_native
|
|
55
|
-
from ansible.module_utils.six import string_types
|
|
56
55
|
from ansible.plugins.lookup import LookupBase
|
|
57
56
|
|
|
58
57
|
|
|
@@ -69,7 +68,7 @@ class LookupModule(LookupBase):
|
|
|
69
68
|
variable_names = list(variables.keys())
|
|
70
69
|
for term in terms:
|
|
71
70
|
|
|
72
|
-
if not isinstance(term,
|
|
71
|
+
if not isinstance(term, str):
|
|
73
72
|
raise AnsibleError('Invalid setting identifier, "%s" is not a string, it is a %s' % (term, type(term)))
|
|
74
73
|
|
|
75
74
|
try:
|
|
@@ -24,12 +24,12 @@ import secrets
|
|
|
24
24
|
import shlex
|
|
25
25
|
import time
|
|
26
26
|
|
|
27
|
-
from collections.abc import Mapping, Sequence
|
|
28
|
-
|
|
29
27
|
from ansible.errors import AnsibleError
|
|
30
28
|
from ansible.module_utils.common.text.converters import to_native
|
|
31
|
-
from ansible.module_utils.six import text_type, string_types
|
|
32
29
|
from ansible.plugins import AnsiblePlugin
|
|
30
|
+
from ansible.utils.display import Display
|
|
31
|
+
|
|
32
|
+
display = Display()
|
|
33
33
|
|
|
34
34
|
_USER_HOME_PATH_RE = re.compile(r'^~[_.A-Za-z0-9][-_.A-Za-z0-9]*$')
|
|
35
35
|
|
|
@@ -84,7 +84,7 @@ class ShellBase(AnsiblePlugin):
|
|
|
84
84
|
return 'ansible-tmp-%s-%s-%s' % (time.time(), os.getpid(), secrets.randbelow(2**48))
|
|
85
85
|
|
|
86
86
|
def env_prefix(self, **kwargs):
|
|
87
|
-
return ' '.join(['%s=%s' % (k, self.quote(
|
|
87
|
+
return ' '.join(['%s=%s' % (k, self.quote(str(v))) for k, v in kwargs.items()])
|
|
88
88
|
|
|
89
89
|
def join_path(self, *args):
|
|
90
90
|
return os.path.join(*args)
|
|
@@ -272,6 +272,11 @@ class ShellBase(AnsiblePlugin):
|
|
|
272
272
|
|
|
273
273
|
def wrap_for_exec(self, cmd):
|
|
274
274
|
"""wrap script execution with any necessary decoration (eg '&' for quoted powershell script paths)"""
|
|
275
|
+
display.deprecated(
|
|
276
|
+
msg='The Shell.wrap_for_exec method is deprecated.',
|
|
277
|
+
help_text="Contact plugin author to update their plugin to not use this method.",
|
|
278
|
+
version='2.24',
|
|
279
|
+
)
|
|
275
280
|
return cmd
|
|
276
281
|
|
|
277
282
|
def quote(self, cmd):
|
|
@@ -192,7 +192,7 @@ class ShellModule(ShellBase):
|
|
|
192
192
|
|
|
193
193
|
def join_path(self, *args):
|
|
194
194
|
# use normpath() to remove doubled slashed and convert forward to backslashes
|
|
195
|
-
parts = [ntpath.normpath(
|
|
195
|
+
parts = [ntpath.normpath(arg) for arg in args]
|
|
196
196
|
|
|
197
197
|
# Because ntpath.join treats any component that begins with a backslash as an absolute path,
|
|
198
198
|
# we have to strip slashes from at least the beginning, otherwise join will ignore all previous
|
|
@@ -210,7 +210,6 @@ class ShellModule(ShellBase):
|
|
|
210
210
|
|
|
211
211
|
def path_has_trailing_slash(self, path):
|
|
212
212
|
# Allow Windows paths to be specified using either slash.
|
|
213
|
-
path = self._unquote(path)
|
|
214
213
|
return path.endswith('/') or path.endswith('\\')
|
|
215
214
|
|
|
216
215
|
def chmod(self, paths, mode):
|
|
@@ -223,11 +222,11 @@ class ShellModule(ShellBase):
|
|
|
223
222
|
raise NotImplementedError('set_user_facl is not implemented for Powershell')
|
|
224
223
|
|
|
225
224
|
def remove(self, path, recurse=False):
|
|
226
|
-
|
|
225
|
+
quoted_path = self._escape(path)
|
|
227
226
|
if recurse:
|
|
228
|
-
return self._encode_script("""Remove-Item '%s' -Force -Recurse;""" %
|
|
227
|
+
return self._encode_script("""Remove-Item '%s' -Force -Recurse;""" % quoted_path)
|
|
229
228
|
else:
|
|
230
|
-
return self._encode_script("""Remove-Item '%s' -Force;""" %
|
|
229
|
+
return self._encode_script("""Remove-Item '%s' -Force;""" % quoted_path)
|
|
231
230
|
|
|
232
231
|
def mkdtemp(
|
|
233
232
|
self,
|
|
@@ -240,7 +239,6 @@ class ShellModule(ShellBase):
|
|
|
240
239
|
# compatibility in case other action plugins outside Ansible calls this.
|
|
241
240
|
if not basefile:
|
|
242
241
|
basefile = self.__class__._generate_temp_dir_name()
|
|
243
|
-
basefile = self._escape(self._unquote(basefile))
|
|
244
242
|
basetmpdir = self._escape(tmpdir if tmpdir else self.get_option('remote_tmp'))
|
|
245
243
|
|
|
246
244
|
script = f"""
|
|
@@ -263,7 +261,6 @@ class ShellModule(ShellBase):
|
|
|
263
261
|
if not basefile:
|
|
264
262
|
basefile = self.__class__._generate_temp_dir_name()
|
|
265
263
|
|
|
266
|
-
basefile = self._unquote(basefile)
|
|
267
264
|
basetmpdir = tmpdir if tmpdir else self.get_option('remote_tmp')
|
|
268
265
|
|
|
269
266
|
script, stdin = _bootstrap_powershell_script("powershell_mkdtemp.ps1", {
|
|
@@ -283,7 +280,6 @@ class ShellModule(ShellBase):
|
|
|
283
280
|
) -> str:
|
|
284
281
|
# This is not called in Ansible anymore but it is kept for backwards
|
|
285
282
|
# compatibility in case other actions plugins outside Ansible called this.
|
|
286
|
-
user_home_path = self._unquote(user_home_path)
|
|
287
283
|
if user_home_path == '~':
|
|
288
284
|
script = 'Write-Output (Get-Location).Path'
|
|
289
285
|
elif user_home_path.startswith('~\\'):
|
|
@@ -297,7 +293,6 @@ class ShellModule(ShellBase):
|
|
|
297
293
|
user_home_path: str,
|
|
298
294
|
username: str = '',
|
|
299
295
|
) -> _ShellCommand:
|
|
300
|
-
user_home_path = self._unquote(user_home_path)
|
|
301
296
|
script, stdin = _bootstrap_powershell_script("powershell_expand_user.ps1", {
|
|
302
297
|
'Path': user_home_path,
|
|
303
298
|
})
|
|
@@ -308,7 +303,7 @@ class ShellModule(ShellBase):
|
|
|
308
303
|
)
|
|
309
304
|
|
|
310
305
|
def exists(self, path):
|
|
311
|
-
path = self._escape(
|
|
306
|
+
path = self._escape(path)
|
|
312
307
|
script = """
|
|
313
308
|
If (Test-Path '%s')
|
|
314
309
|
{
|
|
@@ -329,7 +324,7 @@ class ShellModule(ShellBase):
|
|
|
329
324
|
version="2.23",
|
|
330
325
|
help_text="Use `ActionBase._execute_remote_stat()` instead.",
|
|
331
326
|
)
|
|
332
|
-
path = self._escape(
|
|
327
|
+
path = self._escape(path)
|
|
333
328
|
script = """
|
|
334
329
|
If (Test-Path -PathType Leaf '%(path)s')
|
|
335
330
|
{
|
|
@@ -364,7 +359,7 @@ class ShellModule(ShellBase):
|
|
|
364
359
|
if arg_path:
|
|
365
360
|
# Running a module without the exec_wrapper and with an argument
|
|
366
361
|
# file.
|
|
367
|
-
script_path =
|
|
362
|
+
script_path = cmd_parts[0]
|
|
368
363
|
if not script_path.lower().endswith('.ps1'):
|
|
369
364
|
script_path += '.ps1'
|
|
370
365
|
|
|
@@ -387,7 +382,6 @@ class ShellModule(ShellBase):
|
|
|
387
382
|
cmd_parts.insert(0, shebang[2:])
|
|
388
383
|
elif not shebang:
|
|
389
384
|
# The module is assumed to be a binary
|
|
390
|
-
cmd_parts[0] = self._unquote(cmd_parts[0])
|
|
391
385
|
cmd_parts.append(arg_path)
|
|
392
386
|
script = """
|
|
393
387
|
Try
|
|
@@ -428,19 +422,9 @@ class ShellModule(ShellBase):
|
|
|
428
422
|
return self._encode_script(script, preserve_rc=False)
|
|
429
423
|
|
|
430
424
|
def wrap_for_exec(self, cmd):
|
|
425
|
+
super().wrap_for_exec(cmd)
|
|
431
426
|
return '& %s; exit $LASTEXITCODE' % cmd
|
|
432
427
|
|
|
433
|
-
def _unquote(self, value):
|
|
434
|
-
"""Remove any matching quotes that wrap the given value."""
|
|
435
|
-
value = to_text(value or '')
|
|
436
|
-
m = re.match(r'^\s*?\'(.*?)\'\s*?$', value)
|
|
437
|
-
if m:
|
|
438
|
-
return m.group(1)
|
|
439
|
-
m = re.match(r'^\s*?"(.*?)"\s*?$', value)
|
|
440
|
-
if m:
|
|
441
|
-
return m.group(1)
|
|
442
|
-
return value
|
|
443
|
-
|
|
444
428
|
def _escape(self, value):
|
|
445
429
|
"""Return value escaped for use in PowerShell single quotes."""
|
|
446
430
|
# There are 5 chars that need to be escaped in a single quote.
|
|
@@ -53,6 +53,9 @@ from ansible.utils.sentinel import Sentinel
|
|
|
53
53
|
from ansible.utils.vars import combine_vars
|
|
54
54
|
from ansible.vars.clean import strip_internal_keys, module_response_deepcopy
|
|
55
55
|
|
|
56
|
+
if t.TYPE_CHECKING:
|
|
57
|
+
from ansible.playbook.role_include import IncludeRole
|
|
58
|
+
|
|
56
59
|
display = Display()
|
|
57
60
|
|
|
58
61
|
__all__ = ['StrategyBase']
|
|
@@ -581,7 +584,7 @@ class StrategyBase:
|
|
|
581
584
|
self._variable_manager.set_nonpersistent_facts(
|
|
582
585
|
original_host.name,
|
|
583
586
|
dict(
|
|
584
|
-
ansible_failed_task=original_task.
|
|
587
|
+
ansible_failed_task=original_task.dump_attrs(),
|
|
585
588
|
ansible_failed_result=task_result._return_data,
|
|
586
589
|
),
|
|
587
590
|
)
|
|
@@ -799,7 +802,7 @@ class StrategyBase:
|
|
|
799
802
|
|
|
800
803
|
return ret_results
|
|
801
804
|
|
|
802
|
-
def _copy_included_file(self, included_file: IncludedFile) ->
|
|
805
|
+
def _copy_included_file(self, included_file: IncludedFile) -> TaskInclude | IncludeRole:
|
|
803
806
|
"""
|
|
804
807
|
A proven safe and performant way to create a copy of an included file
|
|
805
808
|
"""
|
ansible/plugins/test/core.py
CHANGED
|
@@ -142,6 +142,9 @@ def regex(value='', pattern='', ignorecase=False, multiline=False, match_type='s
|
|
|
142
142
|
This is likely only useful for `search` and `match` which already
|
|
143
143
|
have their own filters.
|
|
144
144
|
"""
|
|
145
|
+
valid_match_types = ('search', 'match', 'fullmatch')
|
|
146
|
+
if match_type not in valid_match_types:
|
|
147
|
+
raise errors.AnsibleTemplatePluginError(f"Invalid match_type specified. Expected one of: {', '.join(valid_match_types)}.", obj=match_type)
|
|
145
148
|
value = to_text(value, errors='surrogate_or_strict')
|
|
146
149
|
flags = 0
|
|
147
150
|
if ignorecase:
|
|
@@ -149,7 +152,7 @@ def regex(value='', pattern='', ignorecase=False, multiline=False, match_type='s
|
|
|
149
152
|
if multiline:
|
|
150
153
|
flags |= re.M
|
|
151
154
|
_re = re.compile(pattern, flags=flags)
|
|
152
|
-
return bool(getattr(_re, match_type
|
|
155
|
+
return bool(getattr(_re, match_type)(value))
|
|
153
156
|
|
|
154
157
|
|
|
155
158
|
@accept_args_markers
|
ansible/plugins/test/falsy.yml
CHANGED
|
@@ -5,7 +5,7 @@ DOCUMENTATION:
|
|
|
5
5
|
short_description: Pythonic false
|
|
6
6
|
description:
|
|
7
7
|
- This check is a more Python version of what is 'false'.
|
|
8
|
-
- It is the opposite of
|
|
8
|
+
- It is the opposite of P(ansible.builtin.truthy#test).
|
|
9
9
|
options:
|
|
10
10
|
_input:
|
|
11
11
|
description: An expression that can be expressed in a boolean context.
|
ansible/plugins/test/regex.yml
CHANGED
|
@@ -3,7 +3,7 @@ DOCUMENTATION:
|
|
|
3
3
|
author: Ansible Core
|
|
4
4
|
short_description: Does string match regular expression from the start
|
|
5
5
|
description:
|
|
6
|
-
- Compare string against regular expression using Python's match or search functions.
|
|
6
|
+
- Compare string against regular expression using Python's match, fullmatch or search functions.
|
|
7
7
|
options:
|
|
8
8
|
_input:
|
|
9
9
|
description: String to match.
|
|
@@ -22,14 +22,26 @@ DOCUMENTATION:
|
|
|
22
22
|
type: boolean
|
|
23
23
|
default: False
|
|
24
24
|
match_type:
|
|
25
|
-
description:
|
|
25
|
+
description:
|
|
26
|
+
- Decide which function to be used to do the matching.
|
|
26
27
|
type: string
|
|
27
|
-
choices: [match, search]
|
|
28
|
+
choices: [match, search, fullmatch]
|
|
28
29
|
default: search
|
|
29
30
|
|
|
30
|
-
EXAMPLES:
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
EXAMPLES:
|
|
32
|
+
- name: check if string matches regex
|
|
33
|
+
assert:
|
|
34
|
+
that:
|
|
35
|
+
- 'url is regex("example\.com/\w+/foo")'
|
|
36
|
+
vars:
|
|
37
|
+
url: "https://example.com/users/foo/resources/bar"
|
|
38
|
+
|
|
39
|
+
- name: check if string matches regex ignoring case
|
|
40
|
+
assert:
|
|
41
|
+
that:
|
|
42
|
+
- 'url is regex("EXAMPLE\.COM/\w+/foo", ignorecase=True)'
|
|
43
|
+
vars:
|
|
44
|
+
url: "https://Example.com/users/foo/resources/bar"
|
|
33
45
|
|
|
34
46
|
RETURN:
|
|
35
47
|
_value:
|
ansible/plugins/test/truthy.yml
CHANGED
|
@@ -20,5 +20,5 @@ EXAMPLES: |
|
|
|
20
20
|
thisisfalse: '{{ "" is truthy }}'
|
|
21
21
|
RETURN:
|
|
22
22
|
_value:
|
|
23
|
-
description: Returns V(True) if the condition is
|
|
23
|
+
description: Returns V(True) if the condition is "Python truthy", V(False) otherwise.
|
|
24
24
|
type: boolean
|
ansible/release.py
CHANGED
ansible/template/__init__.py
CHANGED
|
@@ -25,7 +25,6 @@ if _t.TYPE_CHECKING: # pragma: nocover
|
|
|
25
25
|
|
|
26
26
|
_display: _t.Final[_Display] = _Display()
|
|
27
27
|
_UNSET = _t.cast(_t.Any, object())
|
|
28
|
-
_TTrustable = _t.TypeVar('_TTrustable', bound=str | _io.IOBase | _t.TextIO | _t.BinaryIO)
|
|
29
28
|
_TRUSTABLE_TYPES = (str, _io.IOBase)
|
|
30
29
|
|
|
31
30
|
AnsibleUndefined = _jinja_common.UndefinedMarker
|
|
@@ -361,7 +360,7 @@ def generate_ansible_template_vars(
|
|
|
361
360
|
return _template_vars.generate_ansible_template_vars(path=path, fullpath=fullpath, dest_path=dest_path, include_ansible_managed=True)
|
|
362
361
|
|
|
363
362
|
|
|
364
|
-
def trust_as_template(value:
|
|
363
|
+
def trust_as_template[T: str | _io.IOBase | _t.TextIO | _t.BinaryIO](value: T) -> T:
|
|
365
364
|
"""
|
|
366
365
|
Returns `value` tagged as trusted for templating.
|
|
367
366
|
Raises a `TypeError` if `value` is not a supported type.
|
|
@@ -385,10 +384,7 @@ def is_trusted_as_template(value: object) -> bool:
|
|
|
385
384
|
return isinstance(value, _TRUSTABLE_TYPES) and _tags.TrustedAsTemplate.is_tagged_on(value)
|
|
386
385
|
|
|
387
386
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
def accept_args_markers(plugin: _TCallable) -> _TCallable:
|
|
387
|
+
def accept_args_markers[T: _t.Callable](plugin: T) -> T:
|
|
392
388
|
"""
|
|
393
389
|
A decorator to mark a Jinja plugin as capable of handling `Marker` values for its top-level arguments.
|
|
394
390
|
Non-decorated plugin invocation is skipped when a top-level argument is a `Marker`, with the first such value substituted as the plugin result.
|
|
@@ -399,7 +395,7 @@ def accept_args_markers(plugin: _TCallable) -> _TCallable:
|
|
|
399
395
|
return plugin
|
|
400
396
|
|
|
401
397
|
|
|
402
|
-
def accept_lazy_markers(plugin:
|
|
398
|
+
def accept_lazy_markers[T: _t.Callable](plugin: T) -> T:
|
|
403
399
|
"""
|
|
404
400
|
A decorator to mark a Jinja plugin as capable of handling `Marker` values retrieved from lazy containers.
|
|
405
401
|
Non-decorated plugins will trigger a `MarkerError` exception when attempting to retrieve a `Marker` from a lazy container.
|
|
@@ -62,6 +62,11 @@ class _AnsibleCollectionConfig(type):
|
|
|
62
62
|
cls._require_finder()
|
|
63
63
|
return [_to_text(p) for p in cls._collection_finder._n_collection_paths]
|
|
64
64
|
|
|
65
|
+
@property
|
|
66
|
+
def _internal_collections(cls):
|
|
67
|
+
cls._require_finder()
|
|
68
|
+
return cls._collection_finder._internal_collections
|
|
69
|
+
|
|
65
70
|
@property
|
|
66
71
|
def default_collection(cls):
|
|
67
72
|
return cls._default_collection
|
|
@@ -26,20 +26,16 @@ from . import _to_bytes, _to_text
|
|
|
26
26
|
from ._collection_config import AnsibleCollectionConfig
|
|
27
27
|
|
|
28
28
|
try:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
from importlib.resources.abc import TraversableResources # type: ignore[import]
|
|
34
|
-
except ImportError:
|
|
35
|
-
# Used with Python 3.9 and 3.10 only
|
|
36
|
-
# This member is still available as an alias up until Python 3.14 but
|
|
37
|
-
# is deprecated as of Python 3.12.
|
|
38
|
-
from importlib.abc import TraversableResources # deprecated: description='TraversableResources move' python_version='3.10'
|
|
29
|
+
# Available on Python >= 3.11
|
|
30
|
+
# We ignore the import error that will trigger when running mypy with
|
|
31
|
+
# older Python versions.
|
|
32
|
+
from importlib.resources.abc import TraversableResources # type: ignore[import]
|
|
39
33
|
except ImportError:
|
|
40
|
-
# Python
|
|
41
|
-
#
|
|
42
|
-
|
|
34
|
+
# Used with Python 3.9 and 3.10 only
|
|
35
|
+
# This member is still available as an alias up until Python 3.14 but
|
|
36
|
+
# is deprecated as of Python 3.12.
|
|
37
|
+
# deprecated: description='TraversableResources move' python_version='3.10'
|
|
38
|
+
from importlib.abc import TraversableResources # type: ignore[assignment,no-redef]
|
|
43
39
|
|
|
44
40
|
# NB: this supports import sanity test providing a different impl
|
|
45
41
|
try:
|
|
@@ -186,7 +182,7 @@ class _AnsibleTraversableResources(TraversableResources):
|
|
|
186
182
|
|
|
187
183
|
|
|
188
184
|
class _AnsibleCollectionFinder:
|
|
189
|
-
def __init__(self, paths=None, scan_sys_paths=True):
|
|
185
|
+
def __init__(self, paths=None, scan_sys_paths=True, internal_collections=None):
|
|
190
186
|
# TODO: accept metadata loader override
|
|
191
187
|
self._ansible_pkg_path = _to_text(os.path.dirname(_to_bytes(sys.modules['ansible'].__file__)))
|
|
192
188
|
|
|
@@ -213,6 +209,7 @@ class _AnsibleCollectionFinder:
|
|
|
213
209
|
if p not in good_paths and os.path.isdir(_to_bytes(os.path.join(p, 'ansible_collections'))):
|
|
214
210
|
good_paths.append(p)
|
|
215
211
|
|
|
212
|
+
self._internal_collections = internal_collections
|
|
216
213
|
self._n_configured_paths = good_paths
|
|
217
214
|
self._n_cached_collection_paths = None
|
|
218
215
|
self._n_cached_collection_qualified_paths = None
|
ansible/utils/context_objects.py
CHANGED
|
@@ -9,14 +9,14 @@ from __future__ import annotations
|
|
|
9
9
|
from abc import ABCMeta
|
|
10
10
|
from collections.abc import Container, Mapping, Sequence, Set
|
|
11
11
|
|
|
12
|
+
from ansible.module_utils._internal import _no_six
|
|
12
13
|
from ansible.module_utils.common.collections import ImmutableDict
|
|
13
|
-
from ansible.module_utils.six import add_metaclass, binary_type, text_type
|
|
14
14
|
from ansible.utils.singleton import Singleton
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def _make_immutable(obj):
|
|
18
18
|
"""Recursively convert a container and objects inside of it into immutable data types"""
|
|
19
|
-
if isinstance(obj, (
|
|
19
|
+
if isinstance(obj, (str, bytes)):
|
|
20
20
|
# Strings first because they are also sequences
|
|
21
21
|
return obj
|
|
22
22
|
elif isinstance(obj, Mapping):
|
|
@@ -79,11 +79,14 @@ class CLIArgs(ImmutableDict):
|
|
|
79
79
|
return cls(vars(options))
|
|
80
80
|
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
class GlobalCLIArgs(CLIArgs):
|
|
82
|
+
class GlobalCLIArgs(CLIArgs, metaclass=_ABCSingleton):
|
|
84
83
|
"""
|
|
85
84
|
Globally hold a parsed copy of cli arguments.
|
|
86
85
|
|
|
87
86
|
Only one of these exist per program as it is for global context
|
|
88
87
|
"""
|
|
89
88
|
pass
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def __getattr__(importable_name):
|
|
92
|
+
return _no_six.deprecate(importable_name, __name__, "binary_type", "text_type", "add_metaclass")
|
ansible/utils/display.py
CHANGED
|
@@ -52,11 +52,10 @@ from ansible.constants import config
|
|
|
52
52
|
from ansible.errors import AnsibleAssertionError, AnsiblePromptInterrupt, AnsiblePromptNoninteractive, AnsibleError
|
|
53
53
|
from ansible._internal._errors import _error_utils, _error_factory
|
|
54
54
|
from ansible._internal import _display_utils
|
|
55
|
-
from ansible.module_utils._internal import _deprecator, _messages
|
|
55
|
+
from ansible.module_utils._internal import _deprecator, _messages, _no_six
|
|
56
56
|
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
|
57
57
|
from ansible.module_utils.datatag import deprecator_from_collection_name
|
|
58
58
|
from ansible._internal._datatag._tags import TrustedAsTemplate
|
|
59
|
-
from ansible.module_utils.six import text_type
|
|
60
59
|
from ansible.module_utils._internal import _traceback, _errors
|
|
61
60
|
from ansible.utils.color import stringc
|
|
62
61
|
from ansible.utils.multiprocessing import context as multiprocessing_context
|
|
@@ -66,8 +65,6 @@ if t.TYPE_CHECKING:
|
|
|
66
65
|
# avoid circular import at runtime
|
|
67
66
|
from ansible.executor.task_queue_manager import FinalQueue
|
|
68
67
|
|
|
69
|
-
P = t.ParamSpec('P')
|
|
70
|
-
|
|
71
68
|
_LIBC = ctypes.cdll.LoadLibrary(ctypes.util.find_library('c'))
|
|
72
69
|
# Set argtypes, to avoid segfault if the wrong type is provided,
|
|
73
70
|
# restype is assumed to be c_int
|
|
@@ -118,7 +115,7 @@ def get_text_width(text: str) -> int:
|
|
|
118
115
|
character and using wcwidth individually, falling back to a value of 0
|
|
119
116
|
for non-printable wide characters.
|
|
120
117
|
"""
|
|
121
|
-
if not isinstance(text,
|
|
118
|
+
if not isinstance(text, str):
|
|
122
119
|
raise TypeError('get_text_width requires text, not %s' % type(text))
|
|
123
120
|
|
|
124
121
|
try:
|
|
@@ -398,7 +395,7 @@ class Display(metaclass=Singleton):
|
|
|
398
395
|
self.b_cowsay = b_cow_path
|
|
399
396
|
|
|
400
397
|
@staticmethod
|
|
401
|
-
def _proxy(
|
|
398
|
+
def _proxy[**P](
|
|
402
399
|
func: c.Callable[t.Concatenate[Display, P], None]
|
|
403
400
|
) -> c.Callable[..., None]:
|
|
404
401
|
@wraps(func)
|
|
@@ -1144,3 +1141,7 @@ def _report_config_warnings(deprecator: _messages.PluginInfo) -> None:
|
|
|
1144
1141
|
# emit any warnings or deprecations
|
|
1145
1142
|
# in the event config fails before display is up, we'll lose warnings -- but that's OK, since everything is broken anyway
|
|
1146
1143
|
_report_config_warnings(_deprecator.ANSIBLE_CORE_DEPRECATOR)
|
|
1144
|
+
|
|
1145
|
+
|
|
1146
|
+
def __getattr__(importable_name):
|
|
1147
|
+
return _no_six.deprecate(importable_name, __name__, "text_type")
|
ansible/utils/encrypt.py
CHANGED
|
@@ -176,11 +176,6 @@ class PasslibHash(BaseHash):
|
|
|
176
176
|
return to_text(result, errors='strict')
|
|
177
177
|
|
|
178
178
|
|
|
179
|
-
def passlib_or_crypt(secret, algorithm, salt=None, salt_size=None, rounds=None, ident=None):
|
|
180
|
-
display.deprecated("passlib_or_crypt API is deprecated in favor of do_encrypt", version='2.20')
|
|
181
|
-
return do_encrypt(secret, algorithm, salt=salt, salt_size=salt_size, rounds=rounds, ident=ident)
|
|
182
|
-
|
|
183
|
-
|
|
184
179
|
def do_encrypt(result, encrypt, salt_size=None, salt=None, ident=None, rounds=None):
|
|
185
180
|
if PASSLIB_AVAILABLE:
|
|
186
181
|
return PasslibHash(encrypt).hash(result, salt=salt, salt_size=salt_size, rounds=rounds, ident=ident)
|
ansible/utils/helpers.py
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
|
-
from ansible.module_utils.
|
|
20
|
+
from ansible.module_utils._internal import _no_six
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
def pct_to_int(value, num_items, min_value=1):
|
|
@@ -25,7 +25,7 @@ def pct_to_int(value, num_items, min_value=1):
|
|
|
25
25
|
Converts a given value to a percentage if specified as "x%",
|
|
26
26
|
otherwise converts the given value to an integer.
|
|
27
27
|
"""
|
|
28
|
-
if isinstance(value,
|
|
28
|
+
if isinstance(value, str) and value.endswith('%'):
|
|
29
29
|
value_pct = int(value.replace("%", ""))
|
|
30
30
|
return int((value_pct / 100.0) * num_items) or min_value
|
|
31
31
|
else:
|
|
@@ -47,3 +47,7 @@ def deduplicate_list(original_list):
|
|
|
47
47
|
"""
|
|
48
48
|
seen = set()
|
|
49
49
|
return [x for x in original_list if x not in seen and not seen.add(x)]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def __getattr__(importable_name):
|
|
53
|
+
return _no_six.deprecate(importable_name, __name__, "string_types")
|
ansible/utils/jsonrpc.py
CHANGED
|
@@ -7,9 +7,9 @@ import json
|
|
|
7
7
|
import pickle
|
|
8
8
|
import traceback
|
|
9
9
|
|
|
10
|
+
from ansible.module_utils._internal import _no_six
|
|
10
11
|
from ansible.module_utils.common.text.converters import to_text
|
|
11
12
|
from ansible.module_utils.connection import ConnectionError
|
|
12
|
-
from ansible.module_utils.six import binary_type, text_type
|
|
13
13
|
from ansible.utils.display import Display
|
|
14
14
|
|
|
15
15
|
display = Display()
|
|
@@ -79,9 +79,9 @@ class JsonRpcServer(object):
|
|
|
79
79
|
|
|
80
80
|
def response(self, result=None):
|
|
81
81
|
response = self.header()
|
|
82
|
-
if isinstance(result,
|
|
82
|
+
if isinstance(result, bytes):
|
|
83
83
|
result = to_text(result)
|
|
84
|
-
if not isinstance(result,
|
|
84
|
+
if not isinstance(result, str):
|
|
85
85
|
response["result_type"] = "pickle"
|
|
86
86
|
result = to_text(pickle.dumps(result), errors='surrogateescape')
|
|
87
87
|
response['result'] = result
|
|
@@ -110,3 +110,7 @@ class JsonRpcServer(object):
|
|
|
110
110
|
|
|
111
111
|
def internal_error(self, data=None):
|
|
112
112
|
return self.error(-32603, 'Internal error', data)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def __getattr__(importable_name):
|
|
116
|
+
return _no_six.deprecate(importable_name, __name__, "binary_type", "text_type")
|