ansible-core 2.16.13__py3-none-any.whl → 2.16.14__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.

@@ -19,6 +19,6 @@
19
19
  from __future__ import (absolute_import, division, print_function)
20
20
  __metaclass__ = type
21
21
 
22
- __version__ = '2.16.13'
22
+ __version__ = '2.16.14'
23
23
  __author__ = 'Ansible, Inc.'
24
24
  __codename__ = "All My Love"
@@ -16,12 +16,11 @@ version_added: historical
16
16
  description:
17
17
  - The M(ansible.builtin.command) module takes the command name followed by a list of space-delimited arguments.
18
18
  - The given command will be executed on all selected nodes.
19
- - The command(s) will not be
20
- processed through the shell, so variables like C($HOSTNAME) and operations
21
- like C("*"), C("<"), C(">"), C("|"), C(";") and C("&") will not work.
19
+ - The command(s) will not be processed through the shell, so operations like C("*"), C("<"), C(">"), C("|"), C(";") and C("&") will not work.
20
+ Also, environment variables are resolved via Python, not shell, see O(expand_argument_vars) and are left unchanged if not matched.
22
21
  Use the M(ansible.builtin.shell) module if you need these features.
23
- - To create C(command) tasks that are easier to read than the ones using space-delimited
24
- arguments, pass parameters using the C(args) L(task keyword,https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html#task)
22
+ - To create C(command) tasks that are easier to read than the ones using space-delimited arguments,
23
+ pass parameters using the C(args) L(task keyword,https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html#task)
25
24
  or use O(cmd) parameter.
26
25
  - Either a free form command or O(cmd) parameter is required, see the examples.
27
26
  - For Windows targets, use the M(ansible.windows.win_command) module instead.
@@ -42,8 +41,8 @@ attributes:
42
41
  options:
43
42
  expand_argument_vars:
44
43
  description:
45
- - Expands the arguments that are variables, for example C($HOME) will be expanded before being passed to the
46
- command to run.
44
+ - Expands the arguments that are variables, for example C($HOME) will be expanded before being passed to the command to run.
45
+ - If a variable is not matched, it is left unchanged, unlike shell substitution which would remove it.
47
46
  - Set to V(false) to disable expansion and treat the value as a literal argument.
48
47
  type: bool
49
48
  default: true
ansible/release.py CHANGED
@@ -19,6 +19,6 @@
19
19
  from __future__ import (absolute_import, division, print_function)
20
20
  __metaclass__ = type
21
21
 
22
- __version__ = '2.16.13'
22
+ __version__ = '2.16.14'
23
23
  __author__ = 'Ansible, Inc.'
24
24
  __codename__ = "All My Love"
@@ -49,7 +49,7 @@ from ansible.module_utils.six import string_types
49
49
  from ansible.module_utils.common.text.converters import to_native, to_text, to_bytes
50
50
  from ansible.module_utils.common.collections import is_sequence
51
51
  from ansible.plugins.loader import filter_loader, lookup_loader, test_loader
52
- from ansible.template.native_helpers import ansible_native_concat, ansible_eval_concat, ansible_concat
52
+ from ansible.template.native_helpers import AnsibleUndefined, ansible_native_concat, ansible_eval_concat, ansible_concat
53
53
  from ansible.template.template import AnsibleJ2Template
54
54
  from ansible.template.vars import AnsibleJ2Vars
55
55
  from ansible.utils.display import Display
@@ -329,35 +329,6 @@ def _wrap_native_text(func):
329
329
  return _update_wrapper(wrapper, func)
330
330
 
331
331
 
332
- class AnsibleUndefined(StrictUndefined):
333
- '''
334
- A custom Undefined class, which returns further Undefined objects on access,
335
- rather than throwing an exception.
336
- '''
337
- def __getattr__(self, name):
338
- if name == '__UNSAFE__':
339
- # AnsibleUndefined should never be assumed to be unsafe
340
- # This prevents ``hasattr(val, '__UNSAFE__')`` from evaluating to ``True``
341
- raise AttributeError(name)
342
- # Return original Undefined object to preserve the first failure context
343
- return self
344
-
345
- def __getitem__(self, key):
346
- # Return original Undefined object to preserve the first failure context
347
- return self
348
-
349
- def __repr__(self):
350
- return 'AnsibleUndefined(hint={0!r}, obj={1!r}, name={2!r})'.format(
351
- self._undefined_hint,
352
- self._undefined_obj,
353
- self._undefined_name
354
- )
355
-
356
- def __contains__(self, item):
357
- # Return original Undefined object to preserve the first failure context
358
- return self
359
-
360
-
361
332
  class AnsibleContext(Context):
362
333
  '''
363
334
  A custom context, which intercepts resolve_or_missing() calls and sets a flag
@@ -7,13 +7,19 @@ __metaclass__ = type
7
7
 
8
8
 
9
9
  import ast
10
+ from collections.abc import Mapping
10
11
  from itertools import islice, chain
11
12
  from types import GeneratorType
12
13
 
14
+ from ansible.module_utils.common.collections import is_sequence
13
15
  from ansible.module_utils.common.text.converters import to_text
14
16
  from ansible.module_utils.six import string_types
15
17
  from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode
16
18
  from ansible.utils.native_jinja import NativeJinjaText
19
+ from ansible.utils.unsafe_proxy import wrap_var
20
+ import ansible.module_utils.compat.typing as t
21
+
22
+ from jinja2.runtime import StrictUndefined
17
23
 
18
24
 
19
25
  _JSON_MAP = {
@@ -30,6 +36,40 @@ class Json2Python(ast.NodeTransformer):
30
36
  return ast.Constant(value=_JSON_MAP[node.id])
31
37
 
32
38
 
39
+ def _is_unsafe(value: t.Any) -> bool:
40
+ """
41
+ Our helper function, which will also recursively check dict and
42
+ list entries due to the fact that they may be repr'd and contain
43
+ a key or value which contains jinja2 syntax and would otherwise
44
+ lose the AnsibleUnsafe value.
45
+ """
46
+ to_check = [value]
47
+ seen = set()
48
+
49
+ while True:
50
+ if not to_check:
51
+ break
52
+
53
+ val = to_check.pop(0)
54
+ val_id = id(val)
55
+
56
+ if val_id in seen:
57
+ continue
58
+ seen.add(val_id)
59
+
60
+ if isinstance(val, AnsibleUndefined):
61
+ continue
62
+ if isinstance(val, Mapping):
63
+ to_check.extend(val.keys())
64
+ to_check.extend(val.values())
65
+ elif is_sequence(val):
66
+ to_check.extend(val)
67
+ elif getattr(val, '__UNSAFE__', False):
68
+ return True
69
+
70
+ return False
71
+
72
+
33
73
  def ansible_eval_concat(nodes):
34
74
  """Return a string of concatenated compiled nodes. Throw an undefined error
35
75
  if any of the nodes is undefined.
@@ -45,17 +85,28 @@ def ansible_eval_concat(nodes):
45
85
  if not head:
46
86
  return ''
47
87
 
88
+ unsafe = False
89
+
48
90
  if len(head) == 1:
49
91
  out = head[0]
50
92
 
51
93
  if isinstance(out, NativeJinjaText):
52
94
  return out
53
95
 
96
+ unsafe = _is_unsafe(out)
54
97
  out = to_text(out)
55
98
  else:
56
99
  if isinstance(nodes, GeneratorType):
57
100
  nodes = chain(head, nodes)
58
- out = ''.join([to_text(v) for v in nodes])
101
+
102
+ out_values = []
103
+ for v in nodes:
104
+ if not unsafe and _is_unsafe(v):
105
+ unsafe = True
106
+
107
+ out_values.append(to_text(v))
108
+
109
+ out = ''.join(out_values)
59
110
 
60
111
  # if this looks like a dictionary, list or bool, convert it to such
61
112
  if out.startswith(('{', '[')) or out in ('True', 'False'):
@@ -70,6 +121,9 @@ def ansible_eval_concat(nodes):
70
121
  except (TypeError, ValueError, SyntaxError, MemoryError):
71
122
  pass
72
123
 
124
+ if unsafe:
125
+ out = wrap_var(out)
126
+
73
127
  return out
74
128
 
75
129
 
@@ -80,7 +134,19 @@ def ansible_concat(nodes):
80
134
 
81
135
  Used in Templar.template() when jinja2_native=False and convert_data=False.
82
136
  """
83
- return ''.join([to_text(v) for v in nodes])
137
+ unsafe = False
138
+ values = []
139
+ for v in nodes:
140
+ if not unsafe and _is_unsafe(v):
141
+ unsafe = True
142
+
143
+ values.append(to_text(v))
144
+
145
+ out = ''.join(values)
146
+ if unsafe:
147
+ out = wrap_var(out)
148
+
149
+ return out
84
150
 
85
151
 
86
152
  def ansible_native_concat(nodes):
@@ -97,6 +163,8 @@ def ansible_native_concat(nodes):
97
163
  if not head:
98
164
  return None
99
165
 
166
+ unsafe = False
167
+
100
168
  if len(head) == 1:
101
169
  out = head[0]
102
170
 
@@ -117,10 +185,21 @@ def ansible_native_concat(nodes):
117
185
  # short-circuit literal_eval for anything other than strings
118
186
  if not isinstance(out, string_types):
119
187
  return out
188
+
189
+ unsafe = _is_unsafe(out)
190
+
120
191
  else:
121
192
  if isinstance(nodes, GeneratorType):
122
193
  nodes = chain(head, nodes)
123
- out = ''.join([to_text(v) for v in nodes])
194
+
195
+ out_values = []
196
+ for v in nodes:
197
+ if not unsafe and _is_unsafe(v):
198
+ unsafe = True
199
+
200
+ out_values.append(to_text(v))
201
+
202
+ out = ''.join(out_values)
124
203
 
125
204
  try:
126
205
  evaled = ast.literal_eval(
@@ -130,10 +209,45 @@ def ansible_native_concat(nodes):
130
209
  ast.parse(out, mode='eval')
131
210
  )
132
211
  except (TypeError, ValueError, SyntaxError, MemoryError):
212
+ if unsafe:
213
+ out = wrap_var(out)
214
+
133
215
  return out
134
216
 
135
217
  if isinstance(evaled, string_types):
136
218
  quote = out[0]
137
- return f'{quote}{evaled}{quote}'
219
+ evaled = f'{quote}{evaled}{quote}'
220
+
221
+ if unsafe:
222
+ evaled = wrap_var(evaled)
138
223
 
139
224
  return evaled
225
+
226
+
227
+ class AnsibleUndefined(StrictUndefined):
228
+ """
229
+ A custom Undefined class, which returns further Undefined objects on access,
230
+ rather than throwing an exception.
231
+ """
232
+ def __getattr__(self, name):
233
+ if name == '__UNSAFE__':
234
+ # AnsibleUndefined should never be assumed to be unsafe
235
+ # This prevents ``hasattr(val, '__UNSAFE__')`` from evaluating to ``True``
236
+ raise AttributeError(name)
237
+ # Return original Undefined object to preserve the first failure context
238
+ return self
239
+
240
+ def __getitem__(self, key):
241
+ # Return original Undefined object to preserve the first failure context
242
+ return self
243
+
244
+ def __repr__(self):
245
+ return 'AnsibleUndefined(hint={0!r}, obj={1!r}, name={2!r})'.format(
246
+ self._undefined_hint,
247
+ self._undefined_obj,
248
+ self._undefined_name
249
+ )
250
+
251
+ def __contains__(self, item):
252
+ # Return original Undefined object to preserve the first failure context
253
+ return self
ansible/vars/hostvars.py CHANGED
@@ -94,11 +94,12 @@ class HostVars(Mapping):
94
94
  return self._find_host(host_name) is not None
95
95
 
96
96
  def __iter__(self):
97
- for host in self._inventory.hosts:
98
- yield host
97
+ # include implicit localhost only if it has variables set
98
+ yield from self._inventory.hosts | {'localhost': self._inventory.localhost} if self._inventory.localhost else {}
99
99
 
100
100
  def __len__(self):
101
- return len(self._inventory.hosts)
101
+ # include implicit localhost only if it has variables set
102
+ return len(self._inventory.hosts) + (1 if self._inventory.localhost else 0)
102
103
 
103
104
  def __repr__(self):
104
105
  out = {}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ansible-core
3
- Version: 2.16.13
3
+ Version: 2.16.14
4
4
  Summary: Radically simple IT automation
5
5
  Home-page: https://ansible.com/
6
6
  Author: Ansible, Inc.
@@ -31,11 +31,11 @@ Classifier: Topic :: Utilities
31
31
  Requires-Python: >=3.10
32
32
  Description-Content-Type: text/markdown
33
33
  License-File: COPYING
34
- Requires-Dist: jinja2 >=3.0.0
35
- Requires-Dist: PyYAML >=5.1
34
+ Requires-Dist: jinja2>=3.0.0
35
+ Requires-Dist: PyYAML>=5.1
36
36
  Requires-Dist: cryptography
37
37
  Requires-Dist: packaging
38
- Requires-Dist: resolvelib <1.1.0,>=0.5.3
38
+ Requires-Dist: resolvelib<1.1.0,>=0.5.3
39
39
 
40
40
  [![PyPI version](https://img.shields.io/pypi/v/ansible-core.svg)](https://pypi.org/project/ansible-core)
41
41
  [![Docs badge](https://img.shields.io/badge/docs-latest-brightgreen.svg)](https://docs.ansible.com/ansible/latest/)
@@ -3,7 +3,7 @@ ansible/__main__.py,sha256=IvyRvY64pT0on94qCLibxgDJ0-7_2CRoaZ5kfGOl54Q,1395
3
3
  ansible/constants.py,sha256=FvX7PDG0GWV91Vszb5-DFKvkR8O2OTpBmIbQk-d51sc,9193
4
4
  ansible/context.py,sha256=OzSlaA_GgGRyyf5I209sy19_eGOX6HXn441W9w_FcvU,2018
5
5
  ansible/keyword_desc.yml,sha256=vE9joFgSeHR4Djl7Bd-HHVCrGByRCrTUmWYZ8LKPZKk,7412
6
- ansible/release.py,sha256=GK4bPFG30Vpf20vpQ8rY3Hf_78IyYnrcb3ZLrrEQRY0,916
6
+ ansible/release.py,sha256=s86Byp3wDq2zAwlJ9mU6TNs7kO0mKiaLoUaIEUBWa0s,916
7
7
  ansible/_vendor/__init__.py,sha256=wJRKH7kI9OzYVY9hgSchOsTNTmTnugpPLGYj9Y5akX0,2086
8
8
  ansible/cli/__init__.py,sha256=6jaX6SS-UBM7pjiUlDsC0y07k3klUjxTR5ZEnDiCmP8,28706
9
9
  ansible/cli/adhoc.py,sha256=suzo4QnsaMjJBk5JlAUd-cpQLs8Ckj6A55CiG9Y8Gns,8247
@@ -140,7 +140,7 @@ ansible/inventory/host.py,sha256=7RZjLiB7M74bejFRflOTa8XPHxMC334qhSo_5VmZrKI,512
140
140
  ansible/inventory/manager.py,sha256=ZwmEF3E2BKOJi9SMVQNz83A2f3raQn6Nyo-rfSNMn2k,29507
141
141
  ansible/module_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
142
142
  ansible/module_utils/_text.py,sha256=F_YfeaxhwmTI16HICAzQS9ZmlKgBDdQ4mqR-Kh--okg,597
143
- ansible/module_utils/ansible_release.py,sha256=GK4bPFG30Vpf20vpQ8rY3Hf_78IyYnrcb3ZLrrEQRY0,916
143
+ ansible/module_utils/ansible_release.py,sha256=s86Byp3wDq2zAwlJ9mU6TNs7kO0mKiaLoUaIEUBWa0s,916
144
144
  ansible/module_utils/api.py,sha256=BTo7stVOANbtd-ngZslaqx70r9t5gfvo44cKyu5SFjU,5837
145
145
  ansible/module_utils/basic.py,sha256=i_lL7YrkhtBewM21t4uIfAgqrGqStyCWwjYiUyqRBi0,87706
146
146
  ansible/module_utils/connection.py,sha256=9Us-d-y1bhC3zNnziQxvYNT4umIaN0OYv8zPaUSdEf0,8447
@@ -285,7 +285,7 @@ ansible/modules/assert.py,sha256=rrvyacnzGt7FU_J9dRPZvb9TuJJ7Ah_u1YfLR7tmyj8,281
285
285
  ansible/modules/async_status.py,sha256=aiYunlP0IhBfKw1jjVEb-MRM1RYCpq8VngPAHdAUY4E,4526
286
286
  ansible/modules/async_wrapper.py,sha256=Uouodh1EMehkZ1zjOksRb5R7xaE83vQMdTE4Chwc2zY,11718
287
287
  ansible/modules/blockinfile.py,sha256=bGhu20J7mc_3qjikLpULl5Pca5CO6tv3Ps9mvxsAts8,15558
288
- ansible/modules/command.py,sha256=yd3Dmls_jWCD-5bCAxjxbGk-AA83bElDii3yRzCNVww,14012
288
+ ansible/modules/command.py,sha256=2d-IgbfL5xCsr-V_g0GBzb63ByyZglDeaaP4yL18yrs,14205
289
289
  ansible/modules/copy.py,sha256=yjF_N7eiQz7naq2bP7SH1ygPMQw9WGL-nOyrn8xQbNM,35906
290
290
  ansible/modules/cron.py,sha256=HlokG4Pcx219oksqbZRLXC61SlpbZSpCFVG-uRL_Qz4,26189
291
291
  ansible/modules/deb822_repository.py,sha256=rZzJzyl7TfVKrcICzYOBJISTrqRYGq8AoWNLwyl6eb0,15693
@@ -640,8 +640,8 @@ ansible/plugins/test/version.yml,sha256=2d55HZGIniPu53z6_bV4C26_1sqRAHJqCwesOU3m
640
640
  ansible/plugins/test/version_compare.yml,sha256=2d55HZGIniPu53z6_bV4C26_1sqRAHJqCwesOU3ma38,3283
641
641
  ansible/plugins/vars/__init__.py,sha256=gfNJZDMgLDlH3d0Uzw_rzgqLGZPJtwpeMxkcsDi2jTk,1384
642
642
  ansible/plugins/vars/host_group_vars.py,sha256=DVv-2ku5ea41iZUyjqOFutCqh2VF4lgDKa0fDVjRZpM,6336
643
- ansible/template/__init__.py,sha256=orkAzf7KwC-UawteDcj8oaGBmmz3kHcbKW3uaVs36g4,41474
644
- ansible/template/native_helpers.py,sha256=-2P4gTC_-3JcEFw4R9SmFrRNUkoWoSlOVLxaPLjCcjY,4417
643
+ ansible/template/__init__.py,sha256=pwJlNdZU8QrFKbEgAbfs3xaP7pzfmvS8IaXOtdAjfEg,40470
644
+ ansible/template/native_helpers.py,sha256=PuX9G_LzlxCrBjeEnKMc41d5Gb9juyDrjkOpf65WS_I,7297
645
645
  ansible/template/template.py,sha256=synOxn1MzR7aNcIUanEsrtasK-jFlzvyJdUcqBdidGw,1667
646
646
  ansible/template/vars.py,sha256=Wl-suFtu88AHRCcIqqR7-lLY_KTlXZTE6D4z_oDLwXM,2819
647
647
  ansible/utils/__init__.py,sha256=1lMXN1i2fFqslda4BmeI5tpYMFP95D5Wpr1AjDJi-SQ,833
@@ -678,11 +678,11 @@ ansible/utils/collection_loader/_collection_meta.py,sha256=THmk42SU58welYL5C-dg3
678
678
  ansible/vars/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
679
679
  ansible/vars/clean.py,sha256=TeNDx7skJFqR0K1ok_cQuvKDjzTrCc7u2qGWTNambQo,6083
680
680
  ansible/vars/fact_cache.py,sha256=4lxkYru1qucTDQ0aSmtc5UDWP-gm3edPmDSuTZ2GCmE,1956
681
- ansible/vars/hostvars.py,sha256=xd9TRpqvqMoZxrzQpbBHV_EAii_CdzSBzCg5Y5kpJr8,5202
681
+ ansible/vars/hostvars.py,sha256=cn0kGxC-gdVTjDkRm3-8kN6wuHKx1b7P3k-5koLxOZA,5431
682
682
  ansible/vars/manager.py,sha256=lIfISTPyRcNfJVWJhhNof36Zmk6xSMUkf9sFxrzCzcI,38180
683
683
  ansible/vars/plugins.py,sha256=RsRU9fiLcJwPIAyTYnmVZglsiEOMCIgQskflavE-XnE,4546
684
684
  ansible/vars/reserved.py,sha256=FBD7n2dnA0CW4I0J1LtWwk2hQqvGW0KTRPcxaRtMKWo,2615
685
- ansible_core-2.16.13.data/scripts/ansible-test,sha256=CYIYL99IxWdVTtDIj3avilIJXhGAmtjuKPPWNuLWuc8,1690
685
+ ansible_core-2.16.14.data/scripts/ansible-test,sha256=CYIYL99IxWdVTtDIj3avilIJXhGAmtjuKPPWNuLWuc8,1690
686
686
  ansible_test/__init__.py,sha256=6e721yAyyyocRKzbCKtQXloAfFP7Aqv0L3zG70uh-4A,190
687
687
  ansible_test/_data/ansible.cfg,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
688
688
  ansible_test/_data/coveragerc,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -771,7 +771,7 @@ ansible_test/_internal/target.py,sha256=Whtb_n0jn4zbiMmX7je5jewgzsRczfXRm_ndYtjT
771
771
  ansible_test/_internal/test.py,sha256=znQmGjKACqDU8T0EAPqcv2qyy0J7M2w4OmyYhwHLqT0,14515
772
772
  ansible_test/_internal/thread.py,sha256=WQoZ2q2ljmEkKHRDkIqwxW7eZbkCKDrG3YZfcaxHzHw,2596
773
773
  ansible_test/_internal/timeout.py,sha256=hT-LirImhAh1iCGIh8JpmECXsiGu6Zetw8BWl1iBIC8,4050
774
- ansible_test/_internal/util.py,sha256=xU7SH0cQ2G1hC-9WyG7_xh-NTyHYveaz2LUxbpYExpU,37781
774
+ ansible_test/_internal/util.py,sha256=fKqx_0AHC9isGTabIXrKaXgGY0IaIeabLIkNkU5T9VE,37821
775
775
  ansible_test/_internal/util_common.py,sha256=wxYutoQap6iemTLRC8c0fGSm3GP0ziAlq4XBV77aZfk,17389
776
776
  ansible_test/_internal/venv.py,sha256=DPHAt4tuoIdP7BOXa75-i4T7Paild8eGDsV2UUKOZ7U,9062
777
777
  ansible_test/_internal/ci/__init__.py,sha256=QOaC_8_wUzqFEbsFCXYAnElWoUo6gB40CXvP9RJ-Iyo,7738
@@ -1001,9 +1001,9 @@ ansible_test/config/cloud-config-vultr.ini.template,sha256=XLKHk3lg_8ReQMdWfZzhh
1001
1001
  ansible_test/config/config.yml,sha256=wb3knoBmZewG3GWOMnRHoVPQWW4vPixKLPMNS6vJmTc,2620
1002
1002
  ansible_test/config/inventory.networking.template,sha256=bFNSk8zNQOaZ_twaflrY0XZ9mLwUbRLuNT0BdIFwvn4,1335
1003
1003
  ansible_test/config/inventory.winrm.template,sha256=1QU8W-GFLnYEw8yY9bVIvUAVvJYPM3hyoijf6-M7T00,1098
1004
- ansible_core-2.16.13.dist-info/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
1005
- ansible_core-2.16.13.dist-info/METADATA,sha256=Sna7hrNPzCzdQ90OwJgYiVk-sChIwtggzLgknWw8bXA,6906
1006
- ansible_core-2.16.13.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
1007
- ansible_core-2.16.13.dist-info/entry_points.txt,sha256=0mpmsrIhODChxKl3eS-NcVQCaMetBn8KdPLtVxQgR64,453
1008
- ansible_core-2.16.13.dist-info/top_level.txt,sha256=IFbRLjAvih1DYzJWg3_F6t4sCzEMxRO7TOMNs6GkYHo,21
1009
- ansible_core-2.16.13.dist-info/RECORD,,
1004
+ ansible_core-2.16.14.dist-info/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
1005
+ ansible_core-2.16.14.dist-info/METADATA,sha256=EyCigudJpuGfdKxu1V4mggIyHsc1DBKzLVlK8iOt87I,6903
1006
+ ansible_core-2.16.14.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
1007
+ ansible_core-2.16.14.dist-info/entry_points.txt,sha256=0mpmsrIhODChxKl3eS-NcVQCaMetBn8KdPLtVxQgR64,453
1008
+ ansible_core-2.16.14.dist-info/top_level.txt,sha256=IFbRLjAvih1DYzJWg3_F6t4sCzEMxRO7TOMNs6GkYHo,21
1009
+ ansible_core-2.16.14.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.3.0)
2
+ Generator: setuptools (75.6.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -974,15 +974,15 @@ class HostConnectionError(ApplicationError):
974
974
  self._callback()
975
975
 
976
976
 
977
- def format_command_output(stdout: str, stderr: str) -> str:
977
+ def format_command_output(stdout: str | None, stderr: str | None) -> str:
978
978
  """Return a formatted string containing the given stdout and stderr (if any)."""
979
979
  message = ''
980
980
 
981
- if stderr := stderr.strip():
981
+ if stderr and (stderr := stderr.strip()):
982
982
  message += '>>> Standard Error\n'
983
983
  message += f'{stderr}{Display.clear}\n'
984
984
 
985
- if stdout := stdout.strip():
985
+ if stdout and (stdout := stdout.strip()):
986
986
  message += '>>> Standard Output\n'
987
987
  message += f'{stdout}{Display.clear}\n'
988
988