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
ansible/modules/dnf5.py CHANGED
@@ -365,7 +365,7 @@ from ansible.module_utils.yumdnf import YumDnf, yumdnf_argument_spec
365
365
 
366
366
  libdnf5 = None
367
367
  # Through dnf5-5.2.12 all exceptions raised through swig became RuntimeError
368
- LIBDNF5_ERROR = RuntimeError
368
+ LIBDNF5_ERRORS = RuntimeError
369
369
 
370
370
 
371
371
  def is_installed(base, spec):
@@ -423,7 +423,9 @@ def is_newer_version_installed(base, spec):
423
423
 
424
424
  try:
425
425
  spec_nevra = next(iter(libdnf5.rpm.Nevra.parse(spec)))
426
- except (LIBDNF5_ERROR, StopIteration):
426
+ except LIBDNF5_ERRORS:
427
+ return False
428
+ except StopIteration:
427
429
  return False
428
430
 
429
431
  spec_version = spec_nevra.get_version()
@@ -517,7 +519,7 @@ class Dnf5Module(YumDnf):
517
519
  os.environ["LANGUAGE"] = os.environ["LANG"] = locale
518
520
 
519
521
  global libdnf5
520
- global LIBDNF5_ERROR
522
+ global LIBDNF5_ERRORS
521
523
  has_dnf = True
522
524
  try:
523
525
  import libdnf5 # type: ignore[import]
@@ -526,7 +528,7 @@ class Dnf5Module(YumDnf):
526
528
 
527
529
  try:
528
530
  import libdnf5.exception # type: ignore[import-not-found]
529
- LIBDNF5_ERROR = libdnf5.exception.Error
531
+ LIBDNF5_ERRORS = (libdnf5.exception.Error, libdnf5.exception.NonLibdnf5Exception)
530
532
  except (ImportError, AttributeError):
531
533
  pass
532
534
 
@@ -581,15 +583,7 @@ class Dnf5Module(YumDnf):
581
583
  if self.conf_file:
582
584
  conf.config_file_path = self.conf_file
583
585
 
584
- try:
585
- base.load_config()
586
- except LIBDNF5_ERROR as e:
587
- self.module.fail_json(
588
- msg=str(e),
589
- conf_file=self.conf_file,
590
- failures=[],
591
- rc=1,
592
- )
586
+ base.load_config()
593
587
 
594
588
  if self.releasever is not None:
595
589
  variables = base.get_vars()
@@ -745,19 +739,13 @@ class Dnf5Module(YumDnf):
745
739
  goal.add_install(spec, settings)
746
740
  elif self.state in {"absent", "removed"}:
747
741
  for spec in self.names:
748
- try:
749
- goal.add_remove(spec, settings)
750
- except LIBDNF5_ERROR as e:
751
- self.module.fail_json(msg=str(e), failures=[], rc=1)
742
+ goal.add_remove(spec, settings)
752
743
  if self.autoremove:
753
744
  for pkg in get_unneeded_pkgs(base):
754
745
  goal.add_rpm_remove(pkg, settings)
755
746
 
756
747
  goal.set_allow_erasing(self.allowerasing)
757
- try:
758
- transaction = goal.resolve()
759
- except LIBDNF5_ERROR as e:
760
- self.module.fail_json(msg=str(e), failures=[], rc=1)
748
+ transaction = goal.resolve()
761
749
 
762
750
  if transaction.get_problems():
763
751
  failures = []
@@ -833,7 +821,11 @@ def main():
833
821
  auto_install_module_deps=dict(type="bool", default=True),
834
822
  )
835
823
  )
836
- Dnf5Module(AnsibleModule(**yumdnf_argument_spec)).run()
824
+ module = AnsibleModule(**yumdnf_argument_spec)
825
+ try:
826
+ Dnf5Module(module).run()
827
+ except LIBDNF5_ERRORS as e:
828
+ module.fail_json(msg=str(e), failures=[], rc=1)
837
829
 
838
830
 
839
831
  if __name__ == "__main__":
ansible/modules/file.py CHANGED
@@ -323,11 +323,8 @@ def get_state(path):
323
323
  return 'file'
324
324
 
325
325
  return 'absent'
326
- except OSError as e:
327
- if e.errno == errno.ENOENT: # It may already have been removed
328
- return 'absent'
329
- else:
330
- raise
326
+ except FileNotFoundError:
327
+ return 'absent'
331
328
 
332
329
 
333
330
  # This should be moved into the common file utilities
@@ -527,12 +524,14 @@ def ensure_absent(path):
527
524
  else:
528
525
  try:
529
526
  os.unlink(b_path)
530
- except OSError as e:
531
- if e.errno != errno.ENOENT: # It may already have been removed
532
- module.fail_json(
533
- msg=f"unlinking failed: {to_native(e)}",
534
- path=path
535
- )
527
+ except FileNotFoundError:
528
+ pass
529
+ except OSError as ex:
530
+ module.fail_json(
531
+ msg="Unlinking failed.",
532
+ path=path,
533
+ exception=ex,
534
+ )
536
535
 
537
536
  result.update({'path': path, 'changed': True, 'diff': diff, 'state': 'absent'})
538
537
  else:
@@ -560,10 +559,11 @@ def execute_touch(path, follow, timestamps):
560
559
  try:
561
560
  open(b_path, 'wb').close()
562
561
  changed = True
563
- except (OSError, IOError) as e:
562
+ except OSError as ex:
564
563
  module.fail_json(
565
- msg=f"Error, could not touch target: {to_native(e, nonstring='simplerepr')}",
566
- path=path
564
+ msg="Error, could not touch target.",
565
+ path=path,
566
+ exception=ex,
567
567
  )
568
568
  # Update the attributes on the file
569
569
  diff = initial_diff(path, 'touch', prev_state)
@@ -894,9 +894,8 @@ def ensure_hardlink(path, src, follow, force, timestamps):
894
894
  if os.path.exists(b_path):
895
895
  try:
896
896
  os.unlink(b_path)
897
- except OSError as e:
898
- if e.errno != errno.ENOENT: # It may already have been removed
899
- raise
897
+ except FileNotFoundError:
898
+ pass
900
899
  os.link(b_src, b_tmppath)
901
900
  os.rename(b_tmppath, b_path)
902
901
  except OSError as e:
ansible/modules/find.py CHANGED
@@ -571,9 +571,9 @@ def main():
571
571
 
572
572
  try:
573
573
  st = os.lstat(fsname)
574
- except (IOError, OSError) as e:
575
- module.warn("Skipped entry '%s' due to this access issue: %s\n" % (fsname, to_text(e)))
576
- skipped[fsname] = to_text(e)
574
+ except OSError as ex:
575
+ module.error_as_warning(f"Skipped entry {fsname!r} due to access issue.", exception=ex)
576
+ skipped[fsname] = str(ex)
577
577
  has_warnings = True
578
578
  continue
579
579
 
@@ -436,6 +436,23 @@ def url_get(module, url, dest, use_proxy, last_mod_time, force, timeout=10, head
436
436
  module.fail_json(msg="failed to create temporary content file: %s" % to_native(e), elapsed=elapsed)
437
437
  f.close()
438
438
  rsp.close()
439
+
440
+ # Since shutil.copyfileobj() will read from HTTPResponse in chunks, HTTPResponse.read() will not recognize
441
+ # if the entire content-length of data was not read. We need to do that validation here, unless a 'chunked'
442
+ # transfer-encoding was used, in which case we will not know content-length because it will not be returned.
443
+ # But in that case, HTTPResponse will behave correctly and recognize an IncompleteRead.
444
+
445
+ is_gzip = info.get('content-encoding') == 'gzip'
446
+
447
+ if not module.check_mode and 'content-length' in info:
448
+ # If data is decompressed, then content-length won't match the amount of data we've read, so skip.
449
+ if not is_gzip or (is_gzip and not decompress):
450
+ st = os.stat(tempname)
451
+ cl = int(info['content-length'])
452
+ if st.st_size != cl:
453
+ diff = cl - st.st_size
454
+ module.fail_json(msg=f'Incomplete read, ({rsp.length=}, {cl=}, {st.st_size=}) failed to read remaining {diff} bytes')
455
+
439
456
  return tempname, info
440
457
 
441
458
 
ansible/modules/git.py CHANGED
@@ -357,11 +357,11 @@ def relocate_repo(module, result, repo_dir, old_repo_dir, worktree_dir):
357
357
  dot_git_file.write('gitdir: %s' % repo_dir)
358
358
  result['git_dir_before'] = old_repo_dir
359
359
  result['git_dir_now'] = repo_dir
360
- except (IOError, OSError) as err:
360
+ except OSError as ex:
361
361
  # if we already moved the .git dir, roll it back
362
362
  if os.path.exists(repo_dir):
363
363
  shutil.move(repo_dir, old_repo_dir)
364
- module.fail_json(msg=u'Unable to move git dir. %s' % to_text(err))
364
+ raise Exception('Unable to move git dir.') from ex
365
365
 
366
366
 
367
367
  def head_splitter(headfile, remote, module=None, fail_on_error=False):
@@ -439,7 +439,7 @@ def write_ssh_wrapper(module):
439
439
  fd, wrapper_path = tempfile.mkstemp(prefix=module.tmpdir + '/')
440
440
  else:
441
441
  raise OSError
442
- except (IOError, OSError):
442
+ except OSError:
443
443
  fd, wrapper_path = tempfile.mkstemp()
444
444
 
445
445
  # use existing git_ssh/ssh_command, fallback to 'ssh'
@@ -824,13 +824,14 @@ def get_head_branch(git_path, module, dest, remote, bare=False):
824
824
  """
825
825
  try:
826
826
  repo_path = get_repo_path(dest, bare)
827
- except (IOError, ValueError) as err:
827
+ except (OSError, ValueError) as ex:
828
828
  # No repo path found
829
829
  # ``.git`` file does not have a valid format for detached Git dir.
830
830
  module.fail_json(
831
831
  msg='Current repo does not have a valid reference to a '
832
832
  'separate Git dir or it refers to the invalid path',
833
- details=to_text(err),
833
+ details=str(ex),
834
+ exception=ex,
834
835
  )
835
836
  # Read .git/HEAD for the name of the branch.
836
837
  # If we're in a detached HEAD state, look up the branch associated with
@@ -1290,13 +1291,14 @@ def main():
1290
1291
  if not module.check_mode:
1291
1292
  relocate_repo(module, result, separate_git_dir, repo_path, dest)
1292
1293
  repo_path = separate_git_dir
1293
- except (IOError, ValueError) as err:
1294
+ except (OSError, ValueError) as ex:
1294
1295
  # No repo path found
1295
1296
  # ``.git`` file does not have a valid format for detached Git dir.
1296
1297
  module.fail_json(
1297
1298
  msg='Current repo does not have a valid reference to a '
1298
1299
  'separate Git dir or it refers to the invalid path',
1299
- details=to_text(err),
1300
+ details=str(ex),
1301
+ exception=ex,
1300
1302
  )
1301
1303
  gitconfig = os.path.join(repo_path, 'config')
1302
1304
 
@@ -1,4 +1,3 @@
1
- #!/usr/bin/python
2
1
  # -*- coding: utf-8 -*-
3
2
 
4
3
  # Copyright: (c) 2013, Hiroaki Nakamura <hnakamur@gmail.com>
@@ -102,7 +102,6 @@ EXAMPLES = r"""
102
102
 
103
103
  import base64
104
104
  import copy
105
- import errno
106
105
  import hashlib
107
106
  import hmac
108
107
  import os
@@ -169,11 +168,10 @@ def enforce_state(module, params):
169
168
  if replace_or_add or found != (state == "present"):
170
169
  try:
171
170
  inf = open(path, "r")
172
- except IOError as e:
173
- if e.errno == errno.ENOENT:
174
- inf = None
175
- else:
176
- module.fail_json(msg="Failed to read %s: %s" % (path, str(e)))
171
+ except FileNotFoundError:
172
+ inf = None
173
+ except OSError as ex:
174
+ raise Exception(f"Failed to read {path!r}.") from ex
177
175
  try:
178
176
  with tempfile.NamedTemporaryFile(mode='w+', dir=os.path.dirname(path), delete=False) as outf:
179
177
  if inf is not None:
@@ -184,8 +182,8 @@ def enforce_state(module, params):
184
182
  inf.close()
185
183
  if state == 'present':
186
184
  outf.write(key)
187
- except (IOError, OSError) as e:
188
- module.fail_json(msg="Failed to write to file %s: %s" % (path, to_native(e)))
185
+ except OSError as ex:
186
+ raise Exception(f"Failed to write to file {path!r}.") from ex
189
187
  else:
190
188
  module.atomic_move(outf.name, path)
191
189
 
@@ -220,9 +218,8 @@ def sanity_check(module, host, key, sshkeygen):
220
218
  try:
221
219
  outf.write(key)
222
220
  outf.flush()
223
- except IOError as e:
224
- module.fail_json(msg="Failed to write to temporary file %s: %s" %
225
- (outf.name, to_native(e)))
221
+ except OSError as ex:
222
+ raise Exception(f"Failed to write to temporary file {outf.name!r}.") from ex
226
223
 
227
224
  sshkeygen_command = [sshkeygen, '-F', host, '-f', outf.name]
228
225
  rc, stdout, stderr = module.run_command(sshkeygen_command)
@@ -337,9 +334,10 @@ def compute_diff(path, found_line, replace_or_add, state, key):
337
334
  }
338
335
  try:
339
336
  inf = open(path, "r")
340
- except IOError as e:
341
- if e.errno == errno.ENOENT:
342
- diff['before_header'] = '/dev/null'
337
+ except FileNotFoundError:
338
+ diff['before_header'] = '/dev/null'
339
+ except OSError:
340
+ pass
343
341
  else:
344
342
  diff['before'] = inf.read()
345
343
  inf.close()
@@ -85,4 +85,10 @@ EXAMPLES = """
85
85
  - httpd
86
86
  - mariadb-server
87
87
  state: latest
88
+
89
+ - name: Use the dnf package manager to install httpd
90
+ ansible.builtin.package:
91
+ name: httpd
92
+ state: present
93
+ use: dnf
88
94
  """
@@ -256,8 +256,8 @@ def main():
256
256
  try:
257
257
  with open(path, 'rb') as f:
258
258
  contents = to_text(f.read(), errors='surrogate_or_strict', encoding=encoding)
259
- except (OSError, IOError) as e:
260
- module.fail_json(msg='Unable to read the contents of %s: %s' % (path, to_text(e)))
259
+ except OSError as ex:
260
+ raise Exception(f"Unable to read the contents of {path!r}.") from ex
261
261
 
262
262
  pattern = u''
263
263
  if params['after'] and params['before']:
@@ -180,7 +180,7 @@ from ansible.module_utils.basic import AnsibleModule
180
180
  from ansible.module_utils.common.locale import get_best_parsable_locale
181
181
  from ansible.module_utils.common.sys_info import get_platform_subclass
182
182
  from ansible.module_utils.service import fail_if_missing, is_systemd_managed
183
- from ansible.module_utils.six import PY2, b
183
+ from ansible.module_utils.six import b
184
184
 
185
185
 
186
186
  class Service(object):
@@ -285,14 +285,8 @@ class Service(object):
285
285
  os._exit(0)
286
286
 
287
287
  # Start the command
288
- if PY2:
289
- # Python 2.6's shlex.split can't handle text strings correctly
290
- cmd = to_bytes(cmd, errors='surrogate_or_strict')
291
- cmd = shlex.split(cmd)
292
- else:
293
- # Python3.x shex.split text strings.
294
- cmd = to_text(cmd, errors='surrogate_or_strict')
295
- cmd = [to_bytes(c, errors='surrogate_or_strict') for c in shlex.split(cmd)]
288
+ cmd = to_text(cmd, errors='surrogate_or_strict')
289
+ cmd = [to_bytes(c, errors='surrogate_or_strict') for c in shlex.split(cmd)]
296
290
  # In either of the above cases, pass a list of byte strings to Popen
297
291
 
298
292
  # chkconfig localizes messages and we're screen scraping so make
ansible/modules/slurp.py CHANGED
@@ -85,7 +85,6 @@ import base64
85
85
  import errno
86
86
 
87
87
  from ansible.module_utils.basic import AnsibleModule
88
- from ansible.module_utils.common.text.converters import to_native
89
88
 
90
89
 
91
90
  def main():
@@ -99,20 +98,18 @@ def main():
99
98
 
100
99
  try:
101
100
  with open(source, 'rb') as source_fh:
102
- source_content = source_fh.read()
103
- except (IOError, OSError) as e:
104
- if e.errno == errno.ENOENT:
105
- msg = "file not found: %s" % source
106
- elif e.errno == errno.EACCES:
107
- msg = "file is not readable: %s" % source
108
- elif e.errno == errno.EISDIR:
109
- msg = "source is a directory and must be a file: %s" % source
101
+ data = base64.b64encode(source_fh.read())
102
+ except OSError as ex:
103
+ if ex.errno == errno.ENOENT:
104
+ msg = f"File not found: {source}"
105
+ elif ex.errno == errno.EACCES:
106
+ msg = f"File is not readable: {source}"
107
+ elif ex.errno == errno.EISDIR:
108
+ msg = f"Source is a directory and must be a file: {source}"
110
109
  else:
111
- msg = "unable to slurp file: %s" % to_native(e, errors='surrogate_then_replace')
110
+ msg = "Unable to slurp file: {source}"
112
111
 
113
- module.fail_json(msg)
114
-
115
- data = base64.b64encode(source_content)
112
+ module.fail_json(msg, exception=ex)
116
113
 
117
114
  module.exit_json(content=data, source=source, encoding='base64')
118
115
 
ansible/modules/stat.py CHANGED
@@ -354,7 +354,6 @@ stat:
354
354
  version_added: 2.3
355
355
  """
356
356
 
357
- import errno
358
357
  import grp
359
358
  import os
360
359
  import pwd
@@ -456,12 +455,11 @@ def main():
456
455
  st = os.stat(b_path)
457
456
  else:
458
457
  st = os.lstat(b_path)
459
- except OSError as e:
460
- if e.errno == errno.ENOENT:
461
- output = {'exists': False}
462
- module.exit_json(changed=False, stat=output)
463
-
464
- module.fail_json(msg=e.strerror)
458
+ except FileNotFoundError:
459
+ output = {'exists': False}
460
+ module.exit_json(changed=False, stat=output)
461
+ except OSError as ex:
462
+ module.fail_json(msg=ex.strerror, exception=ex)
465
463
 
466
464
  # process base results
467
465
  output = format_output(module, path, st)
@@ -1132,8 +1132,8 @@ def main():
1132
1132
  res_args['extract_results'] = handler.unarchive()
1133
1133
  if res_args['extract_results']['rc'] != 0:
1134
1134
  module.fail_json(msg="failed to unpack %s to %s" % (src, dest), **res_args)
1135
- except IOError:
1136
- module.fail_json(msg="failed to unpack %s to %s" % (src, dest), **res_args)
1135
+ except OSError as ex:
1136
+ module.fail_json(f"Failed to unpack {src!r} to {dest!r}.", exception=ex, **res_args)
1137
1137
  else:
1138
1138
  res_args['changed'] = True
1139
1139
 
@@ -1150,8 +1150,8 @@ def main():
1150
1150
 
1151
1151
  try:
1152
1152
  res_args['changed'] = module.set_fs_attributes_if_different(file_args, res_args['changed'], expand=False)
1153
- except (IOError, OSError) as e:
1154
- module.fail_json(msg="Unexpected error when accessing exploded file: %s" % to_native(e), **res_args)
1153
+ except OSError as ex:
1154
+ module.fail_json("Unexpected error when accessing exploded file.", exception=ex, **res_args)
1155
1155
 
1156
1156
  if '/' in filename:
1157
1157
  top_folder_path = filename.split('/')[0]
@@ -1165,8 +1165,8 @@ def main():
1165
1165
  file_args['path'] = "%s/%s" % (dest, f)
1166
1166
  try:
1167
1167
  res_args['changed'] = module.set_fs_attributes_if_different(file_args, res_args['changed'], expand=False)
1168
- except (IOError, OSError) as e:
1169
- module.fail_json(msg="Unexpected error when accessing exploded file: %s" % to_native(e), **res_args)
1168
+ except OSError as ex:
1169
+ module.fail_json("Unexpected error when accessing exploded file.", exception=ex, **res_args)
1170
1170
 
1171
1171
  if module.params['list_files']:
1172
1172
  res_args['files'] = handler.files_in_archive
ansible/modules/user.py CHANGED
@@ -1341,7 +1341,7 @@ class User(object):
1341
1341
  try:
1342
1342
  with open(ssh_public_key_file, 'r') as f:
1343
1343
  ssh_public_key = f.read().strip()
1344
- except IOError:
1344
+ except OSError:
1345
1345
  return None
1346
1346
  return ssh_public_key
1347
1347
 
@@ -380,31 +380,29 @@ class LinuxTCPConnectionInfo(TCPConnectionInfo):
380
380
  if not os.path.isfile(self.source_file[family]):
381
381
  continue
382
382
  try:
383
- f = open(self.source_file[family])
384
- for tcp_connection in f.readlines():
385
- tcp_connection = tcp_connection.strip().split()
386
- if tcp_connection[self.local_address_field] == 'local_address':
387
- continue
388
- if (tcp_connection[self.connection_state_field] not in
389
- [get_connection_state_id(_connection_state) for _connection_state in self.module.params['active_connection_states']]):
390
- continue
391
- (local_ip, local_port) = tcp_connection[self.local_address_field].split(':')
392
- if self.port != local_port:
393
- continue
394
- (remote_ip, remote_port) = tcp_connection[self.remote_address_field].split(':')
395
- if (family, remote_ip) in self.exclude_ips:
396
- continue
397
- if any((
398
- (family, local_ip) in self.ips,
399
- (family, self.match_all_ips[family]) in self.ips,
400
- local_ip.startswith(self.ipv4_mapped_ipv6_address['prefix']) and
401
- (family, self.ipv4_mapped_ipv6_address['match_all']) in self.ips,
402
- )):
403
- active_connections += 1
404
- except IOError as e:
383
+ with open(self.source_file[family]) as f:
384
+ for tcp_connection in f.readlines():
385
+ tcp_connection = tcp_connection.strip().split()
386
+ if tcp_connection[self.local_address_field] == 'local_address':
387
+ continue
388
+ if (tcp_connection[self.connection_state_field] not in
389
+ [get_connection_state_id(_connection_state) for _connection_state in self.module.params['active_connection_states']]):
390
+ continue
391
+ (local_ip, local_port) = tcp_connection[self.local_address_field].split(':')
392
+ if self.port != local_port:
393
+ continue
394
+ (remote_ip, remote_port) = tcp_connection[self.remote_address_field].split(':')
395
+ if (family, remote_ip) in self.exclude_ips:
396
+ continue
397
+ if any((
398
+ (family, local_ip) in self.ips,
399
+ (family, self.match_all_ips[family]) in self.ips,
400
+ local_ip.startswith(self.ipv4_mapped_ipv6_address['prefix']) and
401
+ (family, self.ipv4_mapped_ipv6_address['match_all']) in self.ips,
402
+ )):
403
+ active_connections += 1
404
+ except OSError:
405
405
  pass
406
- finally:
407
- f.close()
408
406
 
409
407
  return active_connections
410
408
 
@@ -549,7 +547,7 @@ def main():
549
547
  try:
550
548
  if not os.access(b_path, os.F_OK):
551
549
  break
552
- except IOError:
550
+ except OSError:
553
551
  break
554
552
  elif port:
555
553
  try:
@@ -609,7 +607,7 @@ def main():
609
607
  break
610
608
  except Exception as e:
611
609
  module.warn('wait_for failed on "%s", unexpected exception(%s): %s.).' % (path, to_native(e.__class__), to_native(e)))
612
- except IOError:
610
+ except OSError:
613
611
  pass
614
612
  elif port:
615
613
  alt_connect_timeout = math.ceil(
@@ -648,8 +646,8 @@ def main():
648
646
  # Shutdown the client socket
649
647
  try:
650
648
  s.shutdown(socket.SHUT_RDWR)
651
- except socket.error as e:
652
- if e.errno != errno.ENOTCONN:
649
+ except OSError as ex:
650
+ if ex.errno != errno.ENOTCONN:
653
651
  raise
654
652
  # else, the server broke the connection on its end, assume it's not ready
655
653
  else:
@@ -661,8 +659,8 @@ def main():
661
659
  # Connection established, success!
662
660
  try:
663
661
  s.shutdown(socket.SHUT_RDWR)
664
- except socket.error as e:
665
- if e.errno != errno.ENOTCONN:
662
+ except OSError as ex:
663
+ if ex.errno != errno.ENOTCONN:
666
664
  raise
667
665
  # else, the server broke the connection on its end, assume it's not ready
668
666
  else:
@@ -502,10 +502,11 @@ class YumRepo:
502
502
  try:
503
503
  with open(self.dest, 'w') as fd:
504
504
  self.repofile.write(fd)
505
- except IOError as e:
505
+ except OSError as ex:
506
506
  self.module.fail_json(
507
- msg=f"Problems handling file {self.dest}.",
508
- details=to_native(e),
507
+ msg=f"Problems handling file {self.dest!r}.",
508
+ details=str(ex),
509
+ exception=ex,
509
510
  )
510
511
  else:
511
512
  try:
ansible/parsing/ajson.py CHANGED
@@ -4,15 +4,13 @@
4
4
  from __future__ import annotations as _annotations
5
5
 
6
6
  # from ansible.utils.display import Display as _Display
7
-
8
-
9
- # DTFIX-RELEASE: The pylint deprecated checker does not detect `Display().deprecated` calls, of which we have many.
10
-
7
+ #
8
+ #
11
9
  # deprecated: description='deprecate ajson' core_version='2.23'
12
10
  # _Display().deprecated(
13
11
  # msg='The `ansible.parsing.ajson` module is deprecated.',
14
12
  # version='2.27',
15
- # help_text="", # DTFIX-RELEASE: complete this help text
13
+ # help_text="", # DTFIX-FUTURE: complete this help text
16
14
  # )
17
15
 
18
16
  # Imported for backward compat
@@ -15,7 +15,7 @@ import typing as t
15
15
 
16
16
  from ansible import constants as C
17
17
  from ansible.errors import AnsibleFileNotFound, AnsibleParserError
18
- from ansible._internal._errors import _utils
18
+ from ansible._internal._errors import _error_utils
19
19
  from ansible.module_utils.basic import is_executable
20
20
  from ansible._internal._datatag._tags import Origin, TrustedAsTemplate, SourceWasEncrypted
21
21
  from ansible.module_utils._internal._datatag import AnsibleTagHelper
@@ -81,12 +81,12 @@ class DataLoader:
81
81
  def load(
82
82
  self,
83
83
  data: str,
84
- file_name: str | None = None, # DTFIX-RELEASE: consider deprecating this in favor of tagging Origin on data
85
- show_content: bool = True, # DTFIX-RELEASE: consider future deprecation, but would need RedactAnnotatedSourceContext public
84
+ file_name: str | None = None, # DTFIX-FUTURE: consider deprecating this in favor of tagging Origin on data
85
+ show_content: bool = True, # DTFIX-FUTURE: consider future deprecation, but would need RedactAnnotatedSourceContext public
86
86
  json_only: bool = False,
87
87
  ) -> t.Any:
88
88
  """Backwards compat for now"""
89
- with _utils.RedactAnnotatedSourceContext.when(not show_content):
89
+ with _error_utils.RedactAnnotatedSourceContext.when(not show_content):
90
90
  return from_yaml(data=data, file_name=file_name, json_only=json_only)
91
91
 
92
92
  def load_from_file(self, file_name: str, cache: str = 'all', unsafe: bool = False, json_only: bool = False, trusted_as_template: bool = False) -> t.Any:
@@ -217,7 +217,7 @@ class DataLoader:
217
217
  except FileNotFoundError as ex:
218
218
  # DTFIX-FUTURE: why not just let the builtin one fly?
219
219
  raise AnsibleFileNotFound("Unable to retrieve file contents.", file_name=file_name) from ex
220
- except (IOError, OSError) as ex:
220
+ except OSError as ex:
221
221
  raise AnsibleParserError(f"An error occurred while trying to read the file {file_name!r}.") from ex
222
222
 
223
223
  data = Origin(path=file_name).tag(data)
@@ -448,7 +448,7 @@ class DataLoader:
448
448
 
449
449
  return real_path
450
450
 
451
- except (IOError, OSError) as ex:
451
+ except OSError as ex:
452
452
  raise AnsibleParserError(f"an error occurred while trying to read the file {to_text(real_path)!r}.") from ex
453
453
 
454
454
  def cleanup_tmp_file(self, file_path: str) -> None: