ansible-core 2.19.0b4__py3-none-any.whl → 2.19.0b6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. ansible/_internal/__init__.py +1 -1
  2. ansible/_internal/_ansiballz/__init__.py +0 -0
  3. ansible/_internal/_ansiballz/_builder.py +101 -0
  4. ansible/_internal/{_ansiballz.py → _ansiballz/_wrapper.py} +11 -11
  5. ansible/_internal/_collection_proxy.py +1 -1
  6. ansible/_internal/_errors/_alarm_timeout.py +66 -0
  7. ansible/_internal/_errors/_captured.py +25 -30
  8. ansible/_internal/_errors/_error_factory.py +89 -0
  9. ansible/_internal/_errors/_error_utils.py +240 -0
  10. ansible/_internal/_errors/_task_timeout.py +28 -0
  11. ansible/_internal/_event_formatting.py +127 -0
  12. ansible/_internal/_json/__init__.py +5 -5
  13. ansible/_internal/_json/_profiles/_cache_persistence.py +2 -0
  14. ansible/_internal/_json/_profiles/_inventory_legacy.py +1 -1
  15. ansible/_internal/_json/_profiles/_legacy.py +3 -11
  16. ansible/_internal/_ssh/__init__.py +0 -0
  17. ansible/_internal/_ssh/_agent_launch.py +91 -0
  18. ansible/{utils → _internal/_ssh}/_ssh_agent.py +55 -93
  19. ansible/_internal/_templating/__init__.py +5 -3
  20. ansible/_internal/_templating/_datatag.py +2 -1
  21. ansible/_internal/_templating/_engine.py +3 -4
  22. ansible/_internal/_templating/_jinja_bits.py +28 -20
  23. ansible/_internal/_templating/_jinja_common.py +18 -27
  24. ansible/_internal/_templating/_jinja_plugins.py +36 -5
  25. ansible/_internal/_templating/_lazy_containers.py +5 -5
  26. ansible/_internal/_templating/_template_vars.py +72 -0
  27. ansible/_internal/_templating/_transform.py +26 -19
  28. ansible/_internal/_templating/_utils.py +1 -1
  29. ansible/_internal/_yaml/_constructor.py +4 -4
  30. ansible/_internal/_yaml/_dumper.py +26 -18
  31. ansible/_internal/_yaml/_errors.py +7 -7
  32. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +1 -1
  33. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +1 -1
  34. ansible/cli/__init__.py +11 -93
  35. ansible/cli/arguments/option_helpers.py +3 -4
  36. ansible/cli/console.py +1 -1
  37. ansible/cli/doc.py +86 -30
  38. ansible/cli/inventory.py +5 -7
  39. ansible/compat/importlib_resources.py +9 -12
  40. ansible/config/base.yml +46 -0
  41. ansible/errors/__init__.py +98 -50
  42. ansible/executor/module_common.py +75 -49
  43. ansible/executor/powershell/async_watchdog.ps1 +2 -2
  44. ansible/executor/powershell/async_wrapper.ps1 +3 -3
  45. ansible/executor/powershell/become_wrapper.ps1 +20 -2
  46. ansible/executor/powershell/bootstrap_wrapper.ps1 +28 -6
  47. ansible/executor/powershell/coverage_wrapper.ps1 +15 -6
  48. ansible/executor/powershell/exec_wrapper.ps1 +219 -6
  49. ansible/executor/powershell/module_manifest.py +52 -0
  50. ansible/executor/powershell/module_wrapper.ps1 +47 -21
  51. ansible/executor/powershell/powershell_expand_user.ps1 +20 -0
  52. ansible/executor/powershell/powershell_mkdtemp.ps1 +17 -0
  53. ansible/executor/process/worker.py +40 -115
  54. ansible/executor/task_executor.py +26 -61
  55. ansible/executor/task_result.py +2 -4
  56. ansible/galaxy/api.py +1 -4
  57. ansible/galaxy/collection/__init__.py +2 -10
  58. ansible/galaxy/collection/concrete_artifact_manager.py +2 -8
  59. ansible/galaxy/role.py +2 -2
  60. ansible/inventory/manager.py +1 -1
  61. ansible/module_utils/_internal/__init__.py +7 -7
  62. ansible/module_utils/_internal/_ambient_context.py +3 -3
  63. ansible/module_utils/_internal/_ansiballz/__init__.py +0 -0
  64. ansible/module_utils/_internal/_ansiballz/_extensions/__init__.py +0 -0
  65. ansible/module_utils/_internal/_ansiballz/_extensions/_coverage.py +45 -0
  66. ansible/module_utils/_internal/_ansiballz/_extensions/_pydevd.py +62 -0
  67. ansible/module_utils/_internal/{_ansiballz.py → _ansiballz/_loader.py} +13 -39
  68. ansible/module_utils/_internal/_ansiballz/_respawn.py +32 -0
  69. ansible/module_utils/_internal/_ansiballz/_respawn_wrapper.py +23 -0
  70. ansible/module_utils/_internal/_datatag/__init__.py +43 -15
  71. ansible/module_utils/_internal/_datatag/_tags.py +2 -2
  72. ansible/module_utils/_internal/_deprecator.py +67 -55
  73. ansible/module_utils/_internal/_errors.py +88 -17
  74. ansible/module_utils/_internal/_event_utils.py +61 -0
  75. ansible/module_utils/_internal/_json/_profiles/__init__.py +22 -4
  76. ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +2 -0
  77. ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +2 -0
  78. ansible/module_utils/_internal/_json/_profiles/_tagless.py +3 -1
  79. ansible/module_utils/{common/messages.py → _internal/_messages.py} +54 -49
  80. ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +1 -3
  81. ansible/module_utils/_internal/_plugin_info.py +15 -2
  82. ansible/module_utils/_internal/_stack.py +22 -0
  83. ansible/module_utils/_internal/_text_utils.py +6 -0
  84. ansible/module_utils/_internal/_traceback.py +11 -8
  85. ansible/module_utils/ansible_release.py +1 -1
  86. ansible/module_utils/basic.py +95 -71
  87. ansible/module_utils/common/arg_spec.py +2 -2
  88. ansible/module_utils/common/collections.py +6 -0
  89. ansible/module_utils/common/json.py +2 -2
  90. ansible/module_utils/common/respawn.py +4 -41
  91. ansible/module_utils/common/text/converters.py +3 -3
  92. ansible/module_utils/common/validation.py +1 -1
  93. ansible/module_utils/common/warnings.py +80 -23
  94. ansible/module_utils/common/yaml.py +1 -1
  95. ansible/module_utils/connection.py +8 -11
  96. ansible/module_utils/datatag.py +5 -2
  97. ansible/module_utils/facts/hardware/linux.py +1 -1
  98. ansible/module_utils/facts/sysctl.py +4 -6
  99. ansible/module_utils/facts/system/caps.py +2 -2
  100. ansible/module_utils/facts/system/distribution.py +16 -3
  101. ansible/module_utils/facts/system/local.py +1 -1
  102. ansible/module_utils/facts/virtual/linux.py +2 -2
  103. ansible/module_utils/service.py +3 -10
  104. ansible/module_utils/urls.py +4 -4
  105. ansible/modules/apt_repository.py +17 -39
  106. ansible/modules/assemble.py +2 -2
  107. ansible/modules/async_status.py +13 -11
  108. ansible/modules/async_wrapper.py +12 -22
  109. ansible/modules/command.py +3 -3
  110. ansible/modules/copy.py +4 -4
  111. ansible/modules/cron.py +1 -1
  112. ansible/modules/dnf5.py +14 -22
  113. ansible/modules/file.py +16 -17
  114. ansible/modules/find.py +3 -3
  115. ansible/modules/get_url.py +17 -0
  116. ansible/modules/git.py +9 -7
  117. ansible/modules/hostname.py +0 -1
  118. ansible/modules/known_hosts.py +12 -14
  119. ansible/modules/package.py +6 -0
  120. ansible/modules/replace.py +2 -2
  121. ansible/modules/service.py +3 -9
  122. ansible/modules/slurp.py +10 -13
  123. ansible/modules/stat.py +5 -7
  124. ansible/modules/unarchive.py +6 -6
  125. ansible/modules/user.py +1 -1
  126. ansible/modules/wait_for.py +28 -30
  127. ansible/modules/yum_repository.py +4 -3
  128. ansible/parsing/ajson.py +3 -5
  129. ansible/parsing/dataloader.py +6 -6
  130. ansible/parsing/mod_args.py +1 -1
  131. ansible/parsing/plugin_docs.py +2 -2
  132. ansible/parsing/utils/yaml.py +3 -3
  133. ansible/parsing/vault/__init__.py +10 -14
  134. ansible/playbook/base.py +7 -2
  135. ansible/playbook/included_file.py +3 -1
  136. ansible/playbook/play_context.py +2 -0
  137. ansible/playbook/playbook_include.py +1 -1
  138. ansible/playbook/taggable.py +19 -8
  139. ansible/playbook/task.py +2 -0
  140. ansible/plugins/__init__.py +0 -25
  141. ansible/plugins/action/__init__.py +8 -31
  142. ansible/plugins/action/add_host.py +1 -1
  143. ansible/plugins/action/assemble.py +8 -16
  144. ansible/plugins/action/async_status.py +7 -2
  145. ansible/plugins/action/copy.py +8 -7
  146. ansible/plugins/action/fetch.py +3 -3
  147. ansible/plugins/action/gather_facts.py +8 -8
  148. ansible/plugins/action/package.py +5 -8
  149. ansible/plugins/action/script.py +8 -15
  150. ansible/plugins/action/service.py +3 -7
  151. ansible/plugins/action/template.py +11 -10
  152. ansible/plugins/action/unarchive.py +5 -15
  153. ansible/plugins/action/uri.py +9 -20
  154. ansible/plugins/cache/__init__.py +17 -19
  155. ansible/plugins/callback/__init__.py +4 -6
  156. ansible/plugins/callback/junit.py +4 -2
  157. ansible/plugins/callback/tree.py +5 -5
  158. ansible/plugins/connection/local.py +6 -6
  159. ansible/plugins/connection/paramiko_ssh.py +5 -5
  160. ansible/plugins/connection/ssh.py +25 -15
  161. ansible/plugins/connection/winrm.py +6 -3
  162. ansible/plugins/doc_fragments/constructed.py +2 -2
  163. ansible/plugins/filter/core.py +32 -27
  164. ansible/plugins/filter/encryption.py +14 -6
  165. ansible/plugins/inventory/__init__.py +11 -10
  166. ansible/plugins/inventory/script.py +1 -1
  167. ansible/plugins/list.py +73 -19
  168. ansible/plugins/loader.py +7 -7
  169. ansible/plugins/lookup/csvfile.py +16 -71
  170. ansible/plugins/lookup/first_found.py +2 -1
  171. ansible/plugins/lookup/template.py +9 -4
  172. ansible/plugins/shell/__init__.py +56 -2
  173. ansible/plugins/shell/powershell.py +67 -9
  174. ansible/plugins/shell/sh.py +10 -5
  175. ansible/plugins/strategy/__init__.py +3 -3
  176. ansible/plugins/test/core.py +22 -16
  177. ansible/plugins/test/finished.yml +1 -1
  178. ansible/plugins/test/uri.py +2 -5
  179. ansible/release.py +1 -1
  180. ansible/template/__init__.py +38 -54
  181. ansible/utils/collection_loader/_collection_finder.py +3 -3
  182. ansible/utils/display.py +124 -138
  183. ansible/utils/galaxy.py +2 -2
  184. ansible/utils/hashing.py +6 -8
  185. ansible/utils/listify.py +6 -4
  186. ansible/utils/path.py +5 -7
  187. ansible/utils/py3compat.py +2 -1
  188. ansible/utils/ssh_functions.py +3 -2
  189. ansible/utils/unsafe_proxy.py +1 -1
  190. ansible/vars/hostvars.py +1 -1
  191. ansible/vars/plugins.py +3 -3
  192. {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/METADATA +1 -1
  193. {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/RECORD +224 -204
  194. {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/WHEEL +1 -1
  195. ansible_test/_data/completion/docker.txt +3 -3
  196. ansible_test/_data/completion/remote.txt +1 -0
  197. ansible_test/_data/requirements/sanity.ansible-doc.txt +1 -1
  198. ansible_test/_data/requirements/sanity.changelog.txt +2 -2
  199. ansible_test/_data/requirements/sanity.pep8.txt +1 -1
  200. ansible_test/_data/requirements/sanity.pylint.txt +4 -4
  201. ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
  202. ansible_test/_internal/commands/integration/coverage.py +7 -2
  203. ansible_test/_internal/host_profiles.py +62 -10
  204. ansible_test/_internal/provisioning.py +10 -4
  205. ansible_test/_internal/ssh.py +1 -5
  206. ansible_test/_internal/thread.py +2 -1
  207. ansible_test/_internal/timeout.py +1 -1
  208. ansible_test/_internal/util.py +40 -12
  209. ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +1 -0
  210. ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +1 -0
  211. ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +1 -0
  212. ansible_test/_util/controller/sanity/pylint/config/collection.cfg +1 -0
  213. ansible_test/_util/controller/sanity/pylint/config/default.cfg +1 -0
  214. ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +61 -7
  215. ansible_test/_util/target/setup/bootstrap.sh +31 -0
  216. ansible_test/_util/target/setup/requirements.py +3 -9
  217. ansible/_internal/_errors/_utils.py +0 -310
  218. {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/entry_points.txt +0 -0
  219. {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/COPYING +0 -0
  220. {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/Apache-License.txt +0 -0
  221. {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
  222. {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/MIT-license.txt +0 -0
  223. {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/PSF-license.txt +0 -0
  224. {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
  225. {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/top_level.txt +0 -0
@@ -33,7 +33,6 @@ import json
33
33
  import pickle
34
34
  import socket
35
35
  import struct
36
- import traceback
37
36
  import uuid
38
37
 
39
38
  from functools import partial
@@ -136,12 +135,11 @@ class Connection(object):
136
135
 
137
136
  try:
138
137
  out = self.send(data)
139
- except socket.error as e:
138
+ except OSError as ex:
140
139
  raise ConnectionError(
141
- 'unable to connect to socket %s. See Troubleshooting socket path issues '
142
- 'in the Network Debug and Troubleshooting Guide' % self.socket_path,
143
- err=to_text(e, errors='surrogate_then_replace'), exception=traceback.format_exc()
144
- )
140
+ f'Unable to connect to socket {self.socket_path!r}. See Troubleshooting socket path issues '
141
+ 'in the Network Debug and Troubleshooting Guide.'
142
+ ) from ex
145
143
 
146
144
  try:
147
145
  response = json.loads(out)
@@ -192,13 +190,12 @@ class Connection(object):
192
190
  send_data(sf, to_bytes(data))
193
191
  response = recv_data(sf)
194
192
 
195
- except socket.error as e:
193
+ except OSError as ex:
196
194
  sf.close()
197
195
  raise ConnectionError(
198
- 'unable to connect to socket %s. See the socket path issue category in '
199
- 'Network Debug and Troubleshooting Guide' % self.socket_path,
200
- err=to_text(e, errors='surrogate_then_replace'), exception=traceback.format_exc()
201
- )
196
+ f'Unable to connect to socket {self.socket_path!r}. See the socket path issue category in '
197
+ 'Network Debug and Troubleshooting Guide.',
198
+ ) from ex
202
199
 
203
200
  sf.close()
204
201
 
@@ -3,13 +3,15 @@ from __future__ import annotations as _annotations
3
3
 
4
4
  import typing as _t
5
5
 
6
- from ._internal import _datatag, _deprecator
6
+ from ._internal import _datatag, _deprecator, _traceback, _messages
7
7
  from ._internal._datatag import _tags
8
- from .common import messages as _messages
9
8
 
10
9
  _T = _t.TypeVar('_T')
11
10
 
12
11
 
12
+ deprecator_from_collection_name = _deprecator.deprecator_from_collection_name
13
+
14
+
13
15
  def deprecate_value(
14
16
  value: _T,
15
17
  msg: str,
@@ -36,6 +38,7 @@ def deprecate_value(
36
38
  date=date,
37
39
  version=version,
38
40
  deprecator=_deprecator.get_best_deprecator(deprecator=deprecator, collection_name=collection_name),
41
+ formatted_traceback=_traceback.maybe_capture_traceback(msg, _traceback.TracebackEvent.DEPRECATED_VALUE),
39
42
  )
40
43
 
41
44
  return deprecated.tag(value)
@@ -182,7 +182,7 @@ class LinuxHardware(Hardware):
182
182
  xen = True
183
183
  # Only interested in the first line
184
184
  break
185
- except IOError:
185
+ except OSError:
186
186
  pass
187
187
 
188
188
  if not os.access("/proc/cpuinfo", os.R_OK):
@@ -17,8 +17,6 @@ from __future__ import annotations
17
17
 
18
18
  import re
19
19
 
20
- from ansible.module_utils.common.text.converters import to_text
21
-
22
20
 
23
21
  def get_sysctl(module, prefixes):
24
22
 
@@ -31,8 +29,8 @@ def get_sysctl(module, prefixes):
31
29
 
32
30
  try:
33
31
  rc, out, err = module.run_command(cmd)
34
- except (IOError, OSError) as e:
35
- module.warn('Unable to read sysctl: %s' % to_text(e))
32
+ except OSError as ex:
33
+ module.error_as_warning('Unable to read sysctl.', exception=ex)
36
34
  rc = 1
37
35
 
38
36
  if rc == 0:
@@ -54,8 +52,8 @@ def get_sysctl(module, prefixes):
54
52
 
55
53
  try:
56
54
  (key, value) = re.split(r'\s?=\s?|: ', line, maxsplit=1)
57
- except Exception as e:
58
- module.warn('Unable to split sysctl line (%s): %s' % (to_text(line), to_text(e)))
55
+ except Exception as ex:
56
+ module.error_as_warning(f'Unable to split sysctl line {line!r}.', exception=ex)
59
57
 
60
58
  if key:
61
59
  sysctl[key] = value.strip()
@@ -38,8 +38,8 @@ class SystemCapabilitiesFactCollector(BaseFactCollector):
38
38
  # NOTE: -> get_caps_data()/parse_caps_data() for easier mocking -akl
39
39
  try:
40
40
  rc, out, err = module.run_command([capsh_path, "--print"], errors='surrogate_then_replace', handle_exceptions=False)
41
- except (IOError, OSError) as e:
42
- module.warn('Could not query system capabilities: %s' % str(e))
41
+ except OSError as ex:
42
+ module.error_as_warning('Could not query system capabilities.', exception=ex)
43
43
 
44
44
  if rc == 0:
45
45
  enforced_caps = []
@@ -310,9 +310,22 @@ class DistributionFiles:
310
310
  suse_facts['distribution_release'] = release.group(1)
311
311
  suse_facts['distribution_version'] = collected_facts['distribution_version'] + '.' + release.group(1)
312
312
 
313
- # See https://www.suse.com/support/kb/doc/?id=000019341 for SLES for SAP
314
- if os.path.islink('/etc/products.d/baseproduct') and os.path.realpath('/etc/products.d/baseproduct').endswith('SLES_SAP.prod'):
315
- suse_facts['distribution'] = 'SLES_SAP'
313
+ # Check VARIANT_ID first for SLES4SAP or SL-Micro
314
+ variant_id_match = re.search(r'^VARIANT_ID="?([^"\n]*)"?', data, re.MULTILINE)
315
+ if variant_id_match:
316
+ variant_id = variant_id_match.group(1)
317
+ if variant_id in ('server-sap', 'sles-sap'):
318
+ suse_facts['distribution'] = 'SLES_SAP'
319
+ elif variant_id == 'transactional':
320
+ suse_facts['distribution'] = 'SL-Micro'
321
+ else:
322
+ # Fallback for older SLES 15 using baseproduct symlink
323
+ if os.path.islink('/etc/products.d/baseproduct'):
324
+ resolved = os.path.realpath('/etc/products.d/baseproduct')
325
+ if resolved.endswith('SLES_SAP.prod'):
326
+ suse_facts['distribution'] = 'SLES_SAP'
327
+ elif resolved.endswith('SL-Micro.prod'):
328
+ suse_facts['distribution'] = 'SL-Micro'
316
329
 
317
330
  return True, suse_facts
318
331
 
@@ -50,7 +50,7 @@ class LocalFactCollector(BaseFactCollector):
50
50
  rc, out, err = module.run_command(fn)
51
51
  if rc != 0:
52
52
  failed = 'Failure executing fact script (%s), rc: %s, err: %s' % (fn, rc, err)
53
- except (IOError, OSError) as e:
53
+ except OSError as e:
54
54
  failed = 'Could not execute fact script (%s): %s' % (fn, to_text(e))
55
55
 
56
56
  if failed is not None:
@@ -129,7 +129,7 @@ class LinuxVirtual(Virtual):
129
129
  for line in get_file_lines('/proc/xen/capabilities'):
130
130
  if "control_d" in line:
131
131
  is_xen_host = True
132
- except IOError:
132
+ except OSError:
133
133
  pass
134
134
 
135
135
  if is_xen_host:
@@ -201,7 +201,7 @@ class LinuxVirtual(Virtual):
201
201
  virtual_facts['virtualization_type'] = 'virtualbox'
202
202
  found_virt = True
203
203
 
204
- if bios_vendor in ('Amazon EC2', 'DigitalOcean', 'Hetzner'):
204
+ if bios_vendor in ('Amazon EC2', 'DigitalOcean', 'Hetzner', 'Linode'):
205
205
  guest_tech.add('kvm')
206
206
  if not found_virt:
207
207
  virtual_facts['virtualization_type'] = 'kvm'
@@ -36,7 +36,7 @@ import select
36
36
  import shlex
37
37
  import subprocess
38
38
 
39
- from ansible.module_utils.six import PY2, b
39
+ from ansible.module_utils.six import b
40
40
  from ansible.module_utils.common.text.converters import to_bytes, to_text
41
41
 
42
42
 
@@ -187,12 +187,8 @@ def daemonize(module, cmd):
187
187
  if pid == 0:
188
188
  os.close(pipe[0])
189
189
 
190
- # if command is string deal with py2 vs py3 conversions for shlex
191
190
  if not isinstance(cmd, list):
192
- if PY2:
193
- cmd = shlex.split(to_bytes(cmd, errors=errors))
194
- else:
195
- cmd = shlex.split(to_text(cmd, errors=errors))
191
+ cmd = shlex.split(to_text(cmd, errors=errors))
196
192
 
197
193
  # make sure we always use byte strings
198
194
  run_cmd = []
@@ -247,9 +243,6 @@ def daemonize(module, cmd):
247
243
  break
248
244
  return_data += to_bytes(data, errors=errors)
249
245
 
250
- # Note: no need to specify encoding on py3 as this module sends the
251
- # pickle to itself (thus same python interpreter so we aren't mixing
252
- # py2 and py3)
253
246
  return pickle.loads(to_bytes(return_data, errors=errors))
254
247
 
255
248
 
@@ -293,7 +286,7 @@ def is_systemd_managed(module):
293
286
  with open('/proc/1/comm', 'r') as init_proc:
294
287
  init = init_proc.readline().strip()
295
288
  return init == 'systemd'
296
- except IOError:
289
+ except OSError:
297
290
  # If comm doesn't exist, old kernel, no systemd
298
291
  return False
299
292
 
@@ -580,7 +580,7 @@ def get_ca_certs(cafile=None, capath=None):
580
580
  cadata[b_der] = None
581
581
  except Exception:
582
582
  continue
583
- except (OSError, IOError):
583
+ except OSError:
584
584
  pass
585
585
 
586
586
  # paths_checked isn't used any more, but is kept just for ease of debugging
@@ -694,7 +694,7 @@ def _configure_auth(url, url_username, url_password, use_gssapi, force_basic_aut
694
694
  try:
695
695
  rc = netrc.netrc(os.environ.get('NETRC'))
696
696
  login = rc.authenticators(parsed.hostname)
697
- except IOError:
697
+ except OSError:
698
698
  login = None
699
699
 
700
700
  if login:
@@ -1303,8 +1303,8 @@ def fetch_url(module, url, data=None, headers=None, method=None,
1303
1303
  except urllib.error.URLError as e:
1304
1304
  code = int(getattr(e, 'code', -1))
1305
1305
  info.update(dict(msg="Request failed: %s" % to_native(e), status=code))
1306
- except socket.error as e:
1307
- info.update(dict(msg="Connection failure: %s" % to_native(e), status=-1))
1306
+ except OSError as ex:
1307
+ info.update(dict(msg=f"Connection failure: {ex}", status=-1))
1308
1308
  except http.client.BadStatusLine as e:
1309
1309
  info.update(dict(msg="Connection failure: connection was closed before a valid response was received: %s" % to_native(e.line), status=-1))
1310
1310
  except Exception as ex:
@@ -88,8 +88,8 @@ options:
88
88
  description:
89
89
  - Whether to automatically try to install the Python apt library or not, if it is not already installed.
90
90
  Without this library, the module does not work.
91
- - Runs C(apt-get install python-apt) for Python 2, and C(apt-get install python3-apt) for Python 3.
92
- - Only works with the system Python 2 or Python 3. If you are using a Python on the remote that is not
91
+ - Runs C(apt-get install python3-apt).
92
+ - Only works with the system Python. If you are using a Python on the remote that is not
93
93
  the system Python, set O(install_python_apt=false) and ensure that the Python apt library
94
94
  for your Python version is installed some other way.
95
95
  type: bool
@@ -98,8 +98,7 @@ author:
98
98
  - Alexander Saltanov (@sashka)
99
99
  version_added: "0.7"
100
100
  requirements:
101
- - python-apt (python 2)
102
- - python3-apt (python 3)
101
+ - python3-apt
103
102
  - apt-key or gpg
104
103
  """
105
104
 
@@ -232,14 +231,15 @@ class SourcesList(object):
232
231
  self.files_mapping = {} # internal DS for tracking symlinks
233
232
  # Repositories that we're adding -- used to implement mode param
234
233
  self.new_repos = set()
235
- self.default_file = self._apt_cfg_file('Dir::Etc::sourcelist')
234
+ self.default_file = apt_pkg.config.find_file('Dir::Etc::sourcelist')
236
235
 
237
236
  # read sources.list if it exists
238
237
  if os.path.isfile(self.default_file):
239
238
  self.load(self.default_file)
240
239
 
241
240
  # read sources.list.d
242
- for file in glob.iglob('%s/*.list' % self._apt_cfg_dir('Dir::Etc::sourceparts')):
241
+ self.sources_dir = apt_pkg.config.find_dir('Dir::Etc::sourceparts')
242
+ for file in glob.iglob(f'{self.sources_dir}/*.list'):
243
243
  if os.path.islink(file):
244
244
  self.files_mapping[file] = os.readlink(file)
245
245
  self.load(file)
@@ -255,7 +255,7 @@ class SourcesList(object):
255
255
  if '/' in filename:
256
256
  return filename
257
257
  else:
258
- return os.path.abspath(os.path.join(self._apt_cfg_dir('Dir::Etc::sourceparts'), filename))
258
+ return os.path.abspath(os.path.join(self.sources_dir, filename))
259
259
 
260
260
  def _suggest_filename(self, line):
261
261
  def _cleanup_filename(s):
@@ -313,28 +313,6 @@ class SourcesList(object):
313
313
 
314
314
  return valid, enabled, source, comment
315
315
 
316
- @staticmethod
317
- def _apt_cfg_file(filespec):
318
- """
319
- Wrapper for `apt_pkg` module for running with Python 2.5
320
- """
321
- try:
322
- result = apt_pkg.config.find_file(filespec)
323
- except AttributeError:
324
- result = apt_pkg.Config.FindFile(filespec)
325
- return result
326
-
327
- @staticmethod
328
- def _apt_cfg_dir(dirspec):
329
- """
330
- Wrapper for `apt_pkg` module for running with Python 2.5
331
- """
332
- try:
333
- result = apt_pkg.config.find_dir(dirspec)
334
- except AttributeError:
335
- result = apt_pkg.Config.FindDir(dirspec)
336
- return result
337
-
338
316
  def load(self, file):
339
317
  group = []
340
318
  f = open(file, 'r')
@@ -355,8 +333,8 @@ class SourcesList(object):
355
333
 
356
334
  try:
357
335
  fd, tmp_path = tempfile.mkstemp(prefix=".%s-" % fn, dir=d)
358
- except (OSError, IOError) as e:
359
- self.module.fail_json(msg='Unable to create temp file at "%s" for apt source: %s' % (d, to_native(e)))
336
+ except OSError as ex:
337
+ raise Exception(f'Unable to create temp file at {d!r} for apt source.') from ex
360
338
 
361
339
  f = os.fdopen(fd, 'w')
362
340
  for n, valid, enabled, source, comment in sources:
@@ -372,8 +350,8 @@ class SourcesList(object):
372
350
 
373
351
  try:
374
352
  f.write(line)
375
- except IOError as ex:
376
- self.module.fail_json(msg="Failed to write to file %s: %s" % (tmp_path, to_native(ex)))
353
+ except OSError as ex:
354
+ raise Exception(f"Failed to write to file {tmp_path!r}.") from ex
377
355
  if filename in self.files_mapping:
378
356
  # Write to symlink target instead of replacing symlink as a normal file
379
357
  self.module.atomic_move(tmp_path, self.files_mapping[filename])
@@ -529,8 +507,8 @@ class UbuntuSourcesList(SourcesList):
529
507
  if os.path.exists(key_file):
530
508
  try:
531
509
  rc, out, err = self.module.run_command([self.gpg_bin, '--list-packets', key_file])
532
- except (IOError, OSError) as e:
533
- self.debug("Could check key against file %s: %s" % (key_file, to_native(e)))
510
+ except OSError as ex:
511
+ self.debug(f"Could check key against file {key_file!r}: {ex}")
534
512
  continue
535
513
 
536
514
  if key_fingerprint in out:
@@ -579,8 +557,8 @@ class UbuntuSourcesList(SourcesList):
579
557
  with open(keyfile, 'wb') as f:
580
558
  f.write(stdout)
581
559
  self.module.log('Added repo key "%s" for apt to file "%s"' % (info['signing_key_fingerprint'], keyfile))
582
- except (OSError, IOError) as e:
583
- self.module.fail_json(msg='Unable to add required signing key for%s ', rc=rc, stderr=stderr, error=to_native(e))
560
+ except OSError as ex:
561
+ self.module.fail_json(msg='Unable to add required signing key.', rc=rc, stderr=stderr, error=str(ex), exception=ex)
584
562
 
585
563
  # apt source file
586
564
  file = file or self._suggest_filename('%s_%s' % (line, self.codename))
@@ -774,9 +752,9 @@ def main():
774
752
  )
775
753
  module.fail_json(msg=msg)
776
754
 
777
- except (OSError, IOError) as ex:
755
+ except OSError as ex:
778
756
  revert_sources_list(sources_before, sources_after, sourceslist_before)
779
- module.fail_json(msg=to_native(ex))
757
+ raise
780
758
 
781
759
  module.exit_json(changed=changed, repo=repo, sources_added=sources_added, sources_removed=sources_removed, state=state, diff=diff)
782
760
 
@@ -186,10 +186,10 @@ def cleanup(module, path, result=None):
186
186
  if os.path.exists(path):
187
187
  try:
188
188
  os.remove(path)
189
- except (IOError, OSError) as e:
189
+ except OSError as ex:
190
190
  # don't error on possible race conditions, but keep warning
191
191
  if result is not None:
192
- module.warn('Unable to remove temp file (%s): %s' % (path, to_native(e)))
192
+ module.error_as_warning(f'Unable to remove temp file {path!r}.', exception=ex)
193
193
 
194
194
 
195
195
  def main():
@@ -28,6 +28,8 @@ options:
28
28
  type: str
29
29
  choices: [ cleanup, status ]
30
30
  default: status
31
+ notes:
32
+ - The RV(started) and RV(finished) return values were updated to return V(True) or V(False) instead of V(1) or V(0) in ansible-core 2.19.
31
33
  extends_documentation_fragment:
32
34
  - action_common_attributes
33
35
  - action_common_attributes.flow
@@ -85,15 +87,15 @@ ansible_job_id:
85
87
  type: str
86
88
  sample: '360874038559.4169'
87
89
  finished:
88
- description: Whether the asynchronous job has finished (V(1)) or not (V(0))
90
+ description: Whether the asynchronous job has finished or not
89
91
  returned: always
90
- type: int
91
- sample: 1
92
+ type: bool
93
+ sample: true
92
94
  started:
93
- description: Whether the asynchronous job has started (V(1)) or not (V(0))
95
+ description: Whether the asynchronous job has started or not
94
96
  returned: always
95
- type: int
96
- sample: 1
97
+ type: bool
98
+ sample: true
97
99
  stdout:
98
100
  description: Any output returned by async_wrapper
99
101
  returned: always
@@ -134,7 +136,7 @@ def main():
134
136
  log_path = os.path.join(async_dir, jid)
135
137
 
136
138
  if not os.path.exists(log_path):
137
- module.fail_json(msg="could not find job", ansible_job_id=jid, started=1, finished=1)
139
+ module.fail_json(msg="could not find job", ansible_job_id=jid, started=True, finished=True)
138
140
 
139
141
  if mode == 'cleanup':
140
142
  os.unlink(log_path)
@@ -151,16 +153,16 @@ def main():
151
153
  except Exception:
152
154
  if not data:
153
155
  # file not written yet? That means it is running
154
- module.exit_json(results_file=log_path, ansible_job_id=jid, started=1, finished=0)
156
+ module.exit_json(results_file=log_path, ansible_job_id=jid, started=True, finished=False)
155
157
  else:
156
158
  module.fail_json(ansible_job_id=jid, results_file=log_path,
157
- msg="Could not parse job output: %s" % data, started=1, finished=1)
159
+ msg="Could not parse job output: %s" % data, started=True, finished=True)
158
160
 
159
161
  if 'started' not in data:
160
- data['finished'] = 1
162
+ data['finished'] = True
161
163
  data['ansible_job_id'] = jid
162
164
  elif 'finished' not in data:
163
- data['finished'] = 0
165
+ data['finished'] = False
164
166
 
165
167
  # just write the module output directly to stdout and exit; bypass other processing done by exit_json since it's already been done
166
168
  print(f"\n{json.dumps(data)}") # pylint: disable=ansible-bad-function
@@ -6,7 +6,6 @@
6
6
  from __future__ import annotations
7
7
 
8
8
 
9
- import errno
10
9
  import json
11
10
  import shlex
12
11
  import shutil
@@ -122,24 +121,14 @@ def _get_interpreter(module_path):
122
121
  return head[2:head.index(b'\n')].strip().split(b' ')
123
122
 
124
123
 
125
- def _make_temp_dir(path):
126
- # TODO: Add checks for permissions on path.
127
- try:
128
- os.makedirs(path)
129
- except OSError as e:
130
- if e.errno != errno.EEXIST:
131
- raise
132
-
133
-
134
124
  def jwrite(info):
135
-
136
125
  jobfile = job_path + ".tmp"
137
126
  tjob = open(jobfile, "w")
138
127
  try:
139
128
  tjob.write(json.dumps(info))
140
- except (IOError, OSError) as e:
141
- notice('failed to write to %s: %s' % (jobfile, str(e)))
142
- raise e
129
+ except OSError as ex:
130
+ notice(f'failed to write to {jobfile!r}: {ex}')
131
+ raise
143
132
  finally:
144
133
  tjob.close()
145
134
  os.rename(jobfile, job_path)
@@ -149,7 +138,7 @@ def _run_module(wrapped_cmd, jid):
149
138
 
150
139
  # DTFIX-FUTURE: needs rework for serialization profiles
151
140
 
152
- jwrite({"started": 1, "finished": 0, "ansible_job_id": jid})
141
+ jwrite({"started": True, "finished": False, "ansible_job_id": jid})
153
142
 
154
143
  result = {}
155
144
 
@@ -200,10 +189,10 @@ def _run_module(wrapped_cmd, jid):
200
189
  result['stderr'] = stderr
201
190
  jwrite(result)
202
191
 
203
- except (OSError, IOError):
192
+ except OSError:
204
193
  e = sys.exc_info()[1]
205
194
  result = {
206
- "failed": 1,
195
+ "failed": True,
207
196
  "cmd": wrapped_cmd,
208
197
  "msg": to_text(e),
209
198
  "outdata": outdata, # temporary notice only
@@ -212,9 +201,9 @@ def _run_module(wrapped_cmd, jid):
212
201
  result['ansible_job_id'] = jid
213
202
  jwrite(result)
214
203
 
215
- except (ValueError, Exception):
204
+ except Exception:
216
205
  result = {
217
- "failed": 1,
206
+ "failed": True,
218
207
  "cmd": wrapped_cmd,
219
208
  "data": outdata, # temporary notice only
220
209
  "stderr": stderr,
@@ -257,10 +246,11 @@ def main():
257
246
  job_path = os.path.join(jobdir, jid)
258
247
 
259
248
  try:
260
- _make_temp_dir(jobdir)
249
+ # TODO: Add checks for permissions on path.
250
+ os.makedirs(jobdir, exist_ok=True)
261
251
  except Exception as e:
262
252
  end({
263
- "failed": 1,
253
+ "failed": True,
264
254
  "msg": "could not create directory: %s - %s" % (jobdir, to_text(e)),
265
255
  "exception": to_text(traceback.format_exc()), # NB: task executor compat will coerce to the correct dataclass type
266
256
  }, 1)
@@ -293,7 +283,7 @@ def main():
293
283
  continue
294
284
 
295
285
  notice("Return async_wrapper task started.")
296
- end({"failed": 0, "started": 1, "finished": 0, "ansible_job_id": jid, "results_file": job_path,
286
+ end({"failed": False, "started": True, "finished": False, "ansible_job_id": jid, "results_file": job_path,
297
287
  "_ansible_suppress_tmpdir_delete": (not preserve_tmp)}, 0)
298
288
  else:
299
289
  # The actual wrapper process
@@ -299,9 +299,9 @@ def main():
299
299
 
300
300
  try:
301
301
  os.chdir(chdir)
302
- except (IOError, OSError) as e:
303
- r['msg'] = 'Unable to change directory before execution: %s' % to_text(e)
304
- module.fail_json(**r)
302
+ except OSError as ex:
303
+ r['msg'] = 'Unable to change directory before execution.'
304
+ module.fail_json(**r, exception=ex)
305
305
 
306
306
  # check_mode partial support, since it only really works in checking creates/removes
307
307
  if module.check_mode:
ansible/modules/copy.py CHANGED
@@ -522,8 +522,8 @@ def main():
522
522
  if os.path.isfile(src):
523
523
  try:
524
524
  checksum_src = module.sha1(src)
525
- except (OSError, IOError) as e:
526
- module.warn("Unable to calculate src checksum, assuming change: %s" % to_native(e))
525
+ except OSError as ex:
526
+ module.error_as_warning("Unable to calculate src checksum, assuming change.", exception=ex)
527
527
  try:
528
528
  # Backwards compat only. This will be None in FIPS mode
529
529
  md5sum_src = module.md5(src)
@@ -636,8 +636,8 @@ def main():
636
636
  # at this point we should always have tmp file
637
637
  module.atomic_move(b_mysrc, dest, unsafe_writes=module.params['unsafe_writes'], keep_dest_attrs=not remote_src)
638
638
 
639
- except (IOError, OSError):
640
- module.fail_json(msg=f"Failed to copy {src!r} to {dest!r}.")
639
+ except OSError as ex:
640
+ raise Exception(f"Failed to copy {src!r} to {dest!r}.") from ex
641
641
  changed = True
642
642
 
643
643
  # If neither have checksums, both src and dest are directories.
ansible/modules/cron.py CHANGED
@@ -271,7 +271,7 @@ class CronTab(object):
271
271
  with open(self.b_cron_file, 'rb') as f:
272
272
  self.n_existing = to_native(f.read(), errors='surrogate_or_strict')
273
273
  self.lines = self.n_existing.splitlines()
274
- except IOError:
274
+ except OSError:
275
275
  # cron file does not exist
276
276
  return
277
277
  except Exception: