ansible-core 2.19.4__py3-none-any.whl → 2.20.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ansible-core might be problematic. Click here for more details.

Files changed (215) hide show
  1. ansible/_internal/__init__.py +1 -4
  2. ansible/_internal/_ansiballz/_builder.py +1 -3
  3. ansible/_internal/_collection_proxy.py +7 -9
  4. ansible/_internal/_json/__init__.py +3 -4
  5. ansible/_internal/_templating/_engine.py +1 -1
  6. ansible/_internal/_templating/_jinja_plugins.py +1 -2
  7. ansible/_internal/_wrapt.py +105 -301
  8. ansible/cli/__init__.py +11 -10
  9. ansible/cli/adhoc.py +1 -2
  10. ansible/cli/arguments/option_helpers.py +1 -1
  11. ansible/cli/config.py +5 -6
  12. ansible/cli/doc.py +67 -67
  13. ansible/cli/galaxy.py +15 -24
  14. ansible/cli/inventory.py +0 -1
  15. ansible/cli/playbook.py +0 -1
  16. ansible/cli/pull.py +0 -1
  17. ansible/cli/scripts/ansible_connection_cli_stub.py +1 -1
  18. ansible/config/base.yml +1 -25
  19. ansible/config/manager.py +0 -2
  20. ansible/executor/play_iterator.py +42 -20
  21. ansible/executor/playbook_executor.py +0 -9
  22. ansible/executor/task_executor.py +26 -18
  23. ansible/executor/task_queue_manager.py +1 -3
  24. ansible/galaxy/api.py +33 -80
  25. ansible/galaxy/collection/__init__.py +11 -21
  26. ansible/galaxy/dependency_resolution/__init__.py +10 -9
  27. ansible/galaxy/dependency_resolution/dataclasses.py +86 -70
  28. ansible/galaxy/dependency_resolution/providers.py +54 -134
  29. ansible/galaxy/dependency_resolution/versioning.py +2 -4
  30. ansible/galaxy/role.py +1 -33
  31. ansible/inventory/manager.py +2 -3
  32. ansible/keyword_desc.yml +0 -3
  33. ansible/module_utils/_internal/_datatag/__init__.py +2 -10
  34. ansible/module_utils/_internal/_no_six.py +86 -0
  35. ansible/module_utils/_text.py +28 -8
  36. ansible/module_utils/ansible_release.py +2 -2
  37. ansible/module_utils/basic.py +26 -23
  38. ansible/module_utils/common/_collections_compat.py +11 -2
  39. ansible/module_utils/common/collections.py +8 -3
  40. ansible/module_utils/common/dict_transformations.py +1 -2
  41. ansible/module_utils/common/network.py +4 -2
  42. ansible/module_utils/common/parameters.py +32 -41
  43. ansible/module_utils/common/text/converters.py +109 -23
  44. ansible/module_utils/common/text/formatters.py +6 -2
  45. ansible/module_utils/common/validation.py +11 -9
  46. ansible/module_utils/connection.py +8 -3
  47. ansible/module_utils/facts/hardware/linux.py +23 -7
  48. ansible/module_utils/facts/hardware/netbsd.py +1 -1
  49. ansible/module_utils/facts/hardware/sunos.py +2 -1
  50. ansible/module_utils/facts/packages.py +6 -2
  51. ansible/module_utils/facts/system/distribution.py +2 -1
  52. ansible/module_utils/facts/system/env.py +6 -3
  53. ansible/module_utils/facts/system/local.py +3 -1
  54. ansible/module_utils/parsing/convert_bool.py +6 -2
  55. ansible/module_utils/service.py +2 -3
  56. ansible/module_utils/six/__init__.py +11 -6
  57. ansible/module_utils/yumdnf.py +0 -5
  58. ansible/modules/apt.py +18 -13
  59. ansible/modules/apt_repository.py +1 -1
  60. ansible/modules/assemble.py +5 -9
  61. ansible/modules/blockinfile.py +39 -23
  62. ansible/modules/cron.py +26 -35
  63. ansible/modules/deb822_repository.py +83 -12
  64. ansible/modules/dnf.py +3 -7
  65. ansible/modules/dnf5.py +4 -6
  66. ansible/modules/expect.py +0 -3
  67. ansible/modules/find.py +1 -2
  68. ansible/modules/get_url.py +1 -1
  69. ansible/modules/git.py +4 -5
  70. ansible/modules/include_vars.py +1 -1
  71. ansible/modules/known_hosts.py +7 -1
  72. ansible/modules/lineinfile.py +71 -63
  73. ansible/modules/package_facts.py +1 -1
  74. ansible/modules/pip.py +8 -2
  75. ansible/modules/replace.py +6 -6
  76. ansible/modules/service.py +3 -4
  77. ansible/modules/stat.py +20 -0
  78. ansible/modules/uri.py +9 -10
  79. ansible/modules/user.py +1 -2
  80. ansible/modules/wait_for.py +2 -2
  81. ansible/modules/wait_for_connection.py +2 -1
  82. ansible/modules/yum_repository.py +1 -16
  83. ansible/parsing/dataloader.py +24 -31
  84. ansible/parsing/vault/__init__.py +1 -2
  85. ansible/playbook/base.py +8 -56
  86. ansible/playbook/block.py +0 -60
  87. ansible/playbook/collectionsearch.py +1 -2
  88. ansible/playbook/handler.py +1 -7
  89. ansible/playbook/helpers.py +0 -7
  90. ansible/playbook/included_file.py +1 -1
  91. ansible/playbook/play.py +102 -36
  92. ansible/playbook/play_context.py +4 -0
  93. ansible/playbook/role/__init__.py +10 -65
  94. ansible/playbook/role/definition.py +3 -4
  95. ansible/playbook/role/include.py +2 -3
  96. ansible/playbook/role/metadata.py +1 -12
  97. ansible/playbook/role/requirement.py +1 -2
  98. ansible/playbook/role_include.py +1 -2
  99. ansible/playbook/taggable.py +16 -5
  100. ansible/playbook/task.py +11 -50
  101. ansible/plugins/action/__init__.py +20 -19
  102. ansible/plugins/action/add_host.py +1 -2
  103. ansible/plugins/action/fetch.py +3 -5
  104. ansible/plugins/action/group_by.py +1 -2
  105. ansible/plugins/action/include_vars.py +20 -22
  106. ansible/plugins/action/script.py +1 -3
  107. ansible/plugins/action/template.py +1 -2
  108. ansible/plugins/action/uri.py +4 -2
  109. ansible/plugins/cache/__init__.py +1 -0
  110. ansible/plugins/callback/__init__.py +13 -6
  111. ansible/plugins/connection/__init__.py +3 -7
  112. ansible/plugins/connection/local.py +2 -3
  113. ansible/plugins/connection/psrp.py +0 -2
  114. ansible/plugins/connection/ssh.py +2 -7
  115. ansible/plugins/connection/winrm.py +0 -2
  116. ansible/plugins/doc_fragments/result_format_callback.py +15 -0
  117. ansible/plugins/filter/core.py +4 -5
  118. ansible/plugins/filter/encryption.py +3 -27
  119. ansible/plugins/filter/mathstuff.py +1 -2
  120. ansible/plugins/filter/to_nice_yaml.yml +31 -3
  121. ansible/plugins/filter/to_yaml.yml +29 -12
  122. ansible/plugins/inventory/__init__.py +1 -2
  123. ansible/plugins/inventory/toml.py +3 -6
  124. ansible/plugins/inventory/yaml.py +1 -2
  125. ansible/plugins/loader.py +3 -4
  126. ansible/plugins/lookup/password.py +1 -2
  127. ansible/plugins/lookup/subelements.py +2 -3
  128. ansible/plugins/lookup/url.py +1 -1
  129. ansible/plugins/lookup/varnames.py +1 -2
  130. ansible/plugins/shell/__init__.py +9 -4
  131. ansible/plugins/shell/powershell.py +8 -24
  132. ansible/plugins/strategy/__init__.py +5 -2
  133. ansible/plugins/test/core.py +4 -1
  134. ansible/plugins/test/falsy.yml +1 -1
  135. ansible/plugins/test/regex.yml +18 -6
  136. ansible/plugins/test/truthy.yml +1 -1
  137. ansible/release.py +2 -2
  138. ansible/template/__init__.py +3 -7
  139. ansible/utils/collection_loader/_collection_config.py +5 -0
  140. ansible/utils/collection_loader/_collection_finder.py +11 -14
  141. ansible/utils/context_objects.py +7 -4
  142. ansible/utils/display.py +7 -6
  143. ansible/utils/encrypt.py +0 -5
  144. ansible/utils/helpers.py +6 -2
  145. ansible/utils/jsonrpc.py +7 -3
  146. ansible/utils/plugin_docs.py +49 -38
  147. ansible/utils/ssh_functions.py +0 -19
  148. ansible/utils/unsafe_proxy.py +7 -7
  149. ansible/vars/clean.py +2 -3
  150. ansible/vars/manager.py +28 -22
  151. ansible/vars/plugins.py +1 -31
  152. {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/METADATA +4 -4
  153. {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/RECORD +213 -214
  154. ansible_test/_data/completion/docker.txt +7 -7
  155. ansible_test/_data/completion/network.txt +0 -1
  156. ansible_test/_data/completion/remote.txt +4 -4
  157. ansible_test/_data/requirements/ansible-test.txt +1 -1
  158. ansible_test/_data/requirements/ansible.txt +1 -1
  159. ansible_test/_data/requirements/sanity.ansible-doc.txt +2 -2
  160. ansible_test/_data/requirements/sanity.changelog.txt +2 -2
  161. ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
  162. ansible_test/_data/requirements/sanity.import.txt +1 -1
  163. ansible_test/_data/requirements/sanity.integration-aliases.txt +1 -1
  164. ansible_test/_data/requirements/sanity.pep8.txt +1 -1
  165. ansible_test/_data/requirements/sanity.pylint.txt +6 -6
  166. ansible_test/_data/requirements/sanity.runtime-metadata.txt +1 -1
  167. ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
  168. ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
  169. ansible_test/_internal/cache.py +2 -5
  170. ansible_test/_internal/cli/compat.py +1 -1
  171. ansible_test/_internal/commands/coverage/combine.py +1 -3
  172. ansible_test/_internal/commands/integration/__init__.py +3 -7
  173. ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
  174. ansible_test/_internal/commands/integration/coverage.py +1 -3
  175. ansible_test/_internal/commands/integration/filters.py +5 -10
  176. ansible_test/_internal/commands/sanity/pylint.py +11 -0
  177. ansible_test/_internal/commands/sanity/validate_modules.py +1 -5
  178. ansible_test/_internal/commands/units/__init__.py +1 -13
  179. ansible_test/_internal/compat/packaging.py +2 -2
  180. ansible_test/_internal/compat/yaml.py +2 -2
  181. ansible_test/_internal/completion.py +2 -5
  182. ansible_test/_internal/config.py +2 -7
  183. ansible_test/_internal/coverage_util.py +1 -1
  184. ansible_test/_internal/delegation.py +2 -0
  185. ansible_test/_internal/docker_util.py +1 -1
  186. ansible_test/_internal/host_profiles.py +6 -11
  187. ansible_test/_internal/provider/__init__.py +2 -5
  188. ansible_test/_internal/provisioning.py +2 -5
  189. ansible_test/_internal/pypi_proxy.py +1 -1
  190. ansible_test/_internal/python_requirements.py +1 -1
  191. ansible_test/_internal/target.py +2 -6
  192. ansible_test/_internal/thread.py +1 -4
  193. ansible_test/_internal/util.py +9 -14
  194. ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +14 -19
  195. ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +48 -45
  196. ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +9 -7
  197. ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +51 -37
  198. ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +31 -18
  199. ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +1 -2
  200. ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +59 -71
  201. ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -2
  202. ansible_test/_util/target/cli/ansible_test_cli_stub.py +4 -2
  203. ansible_test/_util/target/common/constants.py +2 -2
  204. ansible_test/_util/target/setup/bootstrap.sh +0 -6
  205. ansible/utils/py3compat.py +0 -27
  206. ansible_test/_data/pytest/config/legacy.ini +0 -4
  207. {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/WHEEL +0 -0
  208. {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/entry_points.txt +0 -0
  209. {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/licenses/COPYING +0 -0
  210. {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/Apache-License.txt +0 -0
  211. {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
  212. {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/MIT-license.txt +0 -0
  213. {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/PSF-license.txt +0 -0
  214. {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
  215. {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/top_level.txt +0 -0
@@ -24,13 +24,13 @@ import re
24
24
  import sys
25
25
  import time
26
26
 
27
+ from ansible.module_utils._internal import _no_six
27
28
  from ansible.module_utils._internal._concurrent import _futures
28
29
  from ansible.module_utils.common.locale import get_best_parsable_locale
29
30
  from ansible.module_utils.common.text.converters import to_text
30
31
  from ansible.module_utils.common.text.formatters import bytes_to_human
31
32
  from ansible.module_utils.facts.hardware.base import Hardware, HardwareCollector
32
33
  from ansible.module_utils.facts.utils import get_file_content, get_file_lines, get_mount_size
33
- from ansible.module_utils.six import iteritems
34
34
 
35
35
  # import this as a module to ensure we get the same module instance
36
36
  from ansible.module_utils.facts import timeout
@@ -653,7 +653,7 @@ class LinuxHardware(Hardware):
653
653
  retval[target].add(entry)
654
654
  except OSError:
655
655
  continue
656
- return dict((k, list(sorted(v))) for (k, v) in iteritems(retval))
656
+ return dict((k, list(sorted(v))) for (k, v) in retval.items())
657
657
  except OSError:
658
658
  return {}
659
659
 
@@ -665,7 +665,7 @@ class LinuxHardware(Hardware):
665
665
  device = elements[3]
666
666
  target = elements[5]
667
667
  retval[target].add(device)
668
- return dict((k, list(sorted(v))) for (k, v) in iteritems(retval))
668
+ return dict((k, list(sorted(v))) for (k, v) in retval.items())
669
669
  except OSError:
670
670
  return {}
671
671
 
@@ -750,7 +750,7 @@ class LinuxHardware(Hardware):
750
750
  d = {}
751
751
  d['virtual'] = virtual
752
752
  d['links'] = {}
753
- for (link_type, link_values) in iteritems(links):
753
+ for (link_type, link_values) in links.items():
754
754
  d['links'][link_type] = link_values.get(block, [])
755
755
  diskname = os.path.basename(sysdir)
756
756
  for key in ['vendor', 'model', 'sas_address', 'sas_device_handle']:
@@ -801,7 +801,7 @@ class LinuxHardware(Hardware):
801
801
  part_sysdir = sysdir + "/" + partname
802
802
 
803
803
  part['links'] = {}
804
- for (link_type, link_values) in iteritems(links):
804
+ for (link_type, link_values) in links.items():
805
805
  part['links'][link_type] = link_values.get(partname, [])
806
806
 
807
807
  part['start'] = get_file_content(part_sysdir + "/start", 0)
@@ -890,7 +890,8 @@ class LinuxHardware(Hardware):
890
890
  'size_g': items[-2],
891
891
  'free_g': items[-1],
892
892
  'num_lvs': items[2],
893
- 'num_pvs': items[1]
893
+ 'num_pvs': items[1],
894
+ 'lvs': {},
894
895
  }
895
896
 
896
897
  lvs_path = self.module.get_bin_path('lvs')
@@ -901,7 +902,18 @@ class LinuxHardware(Hardware):
901
902
  rc, lv_lines, err = self.module.run_command('%s %s' % (lvs_path, lvm_util_options))
902
903
  for lv_line in lv_lines.splitlines():
903
904
  items = lv_line.strip().split(',')
904
- lvs[items[0]] = {'size_g': items[3], 'vg': items[1]}
905
+ vg_name = items[1]
906
+ lv_name = items[0]
907
+ # The LV name is only unique per VG, so the top level fact lvs can be misleading.
908
+ # TODO: deprecate lvs in favor of vgs
909
+ lvs[lv_name] = {'size_g': items[3], 'vg': vg_name}
910
+ try:
911
+ vgs[vg_name]['lvs'][lv_name] = {'size_g': items[3]}
912
+ except KeyError:
913
+ self.module.warn(
914
+ "An LVM volume group was created while gathering LVM facts, "
915
+ "and is not included in ansible_facts['vgs']."
916
+ )
905
917
 
906
918
  pvs_path = self.module.get_bin_path('pvs')
907
919
  # pvs fields: PV VG #Fmt #Attr PSize PFree
@@ -925,3 +937,7 @@ class LinuxHardwareCollector(HardwareCollector):
925
937
  _fact_class = LinuxHardware
926
938
 
927
939
  required_facts = set(['platform'])
940
+
941
+
942
+ def __getattr__(importable_name):
943
+ return _no_six.deprecate(importable_name, __name__, "iteritems")
@@ -19,7 +19,7 @@ import os
19
19
  import re
20
20
  import time
21
21
 
22
- from ansible.module_utils.six.moves import reduce
22
+ from functools import reduce
23
23
 
24
24
  from ansible.module_utils.facts.hardware.base import Hardware, HardwareCollector
25
25
  from ansible.module_utils.facts.timeout import TimeoutError, timeout
@@ -18,12 +18,13 @@ from __future__ import annotations
18
18
  import re
19
19
  import time
20
20
 
21
+ from functools import reduce
22
+
21
23
  from ansible.module_utils.common.locale import get_best_parsable_locale
22
24
  from ansible.module_utils.common.text.formatters import bytes_to_human
23
25
  from ansible.module_utils.facts.utils import get_file_content, get_mount_size
24
26
  from ansible.module_utils.facts.hardware.base import Hardware, HardwareCollector
25
27
  from ansible.module_utils.facts import timeout
26
- from ansible.module_utils.six.moves import reduce
27
28
 
28
29
 
29
30
  class SunOSHardware(Hardware):
@@ -7,7 +7,7 @@ import ansible.module_utils.compat.typing as t
7
7
 
8
8
  from abc import ABCMeta, abstractmethod
9
9
 
10
- from ansible.module_utils.six import with_metaclass
10
+ from ansible.module_utils._internal import _no_six
11
11
  from ansible.module_utils.basic import missing_required_lib
12
12
  from ansible.module_utils.common.process import get_bin_path
13
13
  from ansible.module_utils.common.respawn import has_respawned, probe_interpreters_for_module, respawn_module
@@ -19,7 +19,7 @@ def get_all_pkg_managers():
19
19
  return {obj.__name__.lower(): obj for obj in get_all_subclasses(PkgMgr) if obj not in (CLIMgr, LibMgr, RespawningLibMgr)}
20
20
 
21
21
 
22
- class PkgMgr(with_metaclass(ABCMeta, object)): # type: ignore[misc]
22
+ class PkgMgr(metaclass=ABCMeta):
23
23
 
24
24
  @abstractmethod
25
25
  def is_available(self, handle_exceptions):
@@ -125,3 +125,7 @@ class CLIMgr(PkgMgr):
125
125
  if not handle_exceptions:
126
126
  raise
127
127
  return found
128
+
129
+
130
+ def __getattr__(importable_name):
131
+ return _no_six.deprecate(importable_name, __name__, "with_metaclass")
@@ -529,7 +529,8 @@ class Distribution(object):
529
529
  'EuroLinux', 'Kylin Linux Advanced Server', 'MIRACLE'],
530
530
  'Debian': ['Debian', 'Ubuntu', 'Raspbian', 'Neon', 'KDE neon',
531
531
  'Linux Mint', 'SteamOS', 'Devuan', 'Kali', 'Cumulus Linux',
532
- 'Pop!_OS', 'Parrot', 'Pardus GNU/Linux', 'Uos', 'Deepin', 'OSMC', 'Linux Mint Debian Edition'],
532
+ 'Pop!_OS', 'Parrot', 'Pardus GNU/Linux', 'Uos', 'Deepin', 'OSMC',
533
+ 'Linux Mint Debian Edition', 'Univention Corporate Server'],
533
534
  'Suse': ['SuSE', 'SLES', 'SLED', 'openSUSE', 'openSUSE Tumbleweed',
534
535
  'SLES_SAP', 'SUSE_LINUX', 'openSUSE Leap', 'ALP-Dolomite', 'SL-Micro',
535
536
  'openSUSE MicroOS'],
@@ -18,8 +18,7 @@ from __future__ import annotations
18
18
  import os
19
19
  import typing as t
20
20
 
21
- from ansible.module_utils.six import iteritems
22
-
21
+ from ansible.module_utils._internal import _no_six
23
22
  from ansible.module_utils.facts.collector import BaseFactCollector
24
23
 
25
24
 
@@ -31,7 +30,11 @@ class EnvFactCollector(BaseFactCollector):
31
30
  env_facts = {}
32
31
  env_facts['env'] = {}
33
32
 
34
- for k, v in iteritems(os.environ):
33
+ for k, v in os.environ.items():
35
34
  env_facts['env'][k] = v
36
35
 
37
36
  return env_facts
37
+
38
+
39
+ def __getattr__(importable_name):
40
+ return _no_six.deprecate(importable_name, __name__, "iteritems")
@@ -3,16 +3,18 @@
3
3
 
4
4
  from __future__ import annotations
5
5
 
6
+ import configparser
6
7
  import glob
7
8
  import json
8
9
  import os
9
10
  import stat
10
11
  import typing as t
11
12
 
13
+ from io import StringIO
14
+
12
15
  from ansible.module_utils.common.text.converters import to_text
13
16
  from ansible.module_utils.facts.utils import get_file_content
14
17
  from ansible.module_utils.facts.collector import BaseFactCollector
15
- from ansible.module_utils.six.moves import configparser, StringIO
16
18
 
17
19
 
18
20
  class LocalFactCollector(BaseFactCollector):
@@ -5,7 +5,7 @@ from __future__ import annotations
5
5
 
6
6
  import collections.abc as c
7
7
 
8
- from ansible.module_utils.six import binary_type, text_type
8
+ from ansible.module_utils._internal import _no_six
9
9
  from ansible.module_utils.common.text.converters import to_text
10
10
 
11
11
 
@@ -20,7 +20,7 @@ def boolean(value, strict=True):
20
20
 
21
21
  normalized_value = value
22
22
 
23
- if isinstance(value, (text_type, binary_type)):
23
+ if isinstance(value, (str, bytes)):
24
24
  normalized_value = to_text(value, errors='surrogate_or_strict').lower().strip()
25
25
 
26
26
  if not isinstance(value, c.Hashable):
@@ -32,3 +32,7 @@ def boolean(value, strict=True):
32
32
  return False
33
33
 
34
34
  raise TypeError("The value '%s' is not a valid boolean. Valid booleans include: %s" % (to_text(value), ', '.join(repr(i) for i in BOOLEANS)))
35
+
36
+
37
+ def __getattr__(importable_name):
38
+ return _no_six.deprecate(importable_name, __name__, "binary_type", "text_type")
@@ -36,7 +36,6 @@ import select
36
36
  import shlex
37
37
  import subprocess
38
38
 
39
- from ansible.module_utils.six import b
40
39
  from ansible.module_utils.common.text.converters import to_bytes, to_text
41
40
 
42
41
 
@@ -200,7 +199,7 @@ def daemonize(module, cmd):
200
199
  fds = [p.stdout, p.stderr]
201
200
 
202
201
  # loop reading output till it is done
203
- output = {p.stdout: b(""), p.stderr: b("")}
202
+ output = {p.stdout: b"", p.stderr: b""}
204
203
  while fds:
205
204
  rfd, wfd, efd = select.select(fds, [], fds, 1)
206
205
  if (rfd + wfd + efd) or p.poll() is None:
@@ -234,7 +233,7 @@ def daemonize(module, cmd):
234
233
  os.waitpid(pid, 0)
235
234
 
236
235
  # Grab response data after child finishes
237
- return_data = b("")
236
+ return_data = b""
238
237
  while True:
239
238
  rfd, wfd, efd = select.select([pipe[0]], [], [pipe[0]])
240
239
  if pipe[0] in rfd:
@@ -3,7 +3,7 @@
3
3
  # upstream vendored file that we're not going to modify on our own
4
4
  # pylint: disable=undefined-variable
5
5
  #
6
- # Copyright (c) 2010-2020 Benjamin Peterson
6
+ # Copyright (c) 2010-2024 Benjamin Peterson
7
7
  #
8
8
  # Permission is hereby granted, free of charge, to any person obtaining a copy
9
9
  # of this software and associated documentation files (the "Software"), to deal
@@ -35,10 +35,10 @@ import types
35
35
 
36
36
  # The following makes it easier for us to script updates of the bundled code. It is not part of
37
37
  # upstream six
38
- _BUNDLED_METADATA = {"pypi_name": "six", "version": "1.16.0"}
38
+ _BUNDLED_METADATA = {"pypi_name": "six", "version": "1.17.0"}
39
39
 
40
40
  __author__ = "Benjamin Peterson <benjamin@python.org>"
41
- __version__ = "1.16.0"
41
+ __version__ = "1.17.0"
42
42
 
43
43
 
44
44
  # Useful for very coarse version differentiation.
@@ -273,7 +273,7 @@ _moved_attributes = [
273
273
  MovedAttribute("reduce", "__builtin__", "functools"),
274
274
  MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
275
275
  MovedAttribute("StringIO", "StringIO", "io"),
276
- MovedAttribute("UserDict", "UserDict", "collections"),
276
+ MovedAttribute("UserDict", "UserDict", "collections", "IterableUserDict", "UserDict"),
277
277
  MovedAttribute("UserList", "UserList", "collections"),
278
278
  MovedAttribute("UserString", "UserString", "collections"),
279
279
  MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
@@ -445,12 +445,17 @@ _urllib_request_moved_attributes = [
445
445
  MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"),
446
446
  MovedAttribute("urlretrieve", "urllib", "urllib.request"),
447
447
  MovedAttribute("urlcleanup", "urllib", "urllib.request"),
448
- MovedAttribute("URLopener", "urllib", "urllib.request"),
449
- MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
450
448
  MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
451
449
  MovedAttribute("parse_http_list", "urllib2", "urllib.request"),
452
450
  MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"),
453
451
  ]
452
+ if sys.version_info[:2] < (3, 14):
453
+ _urllib_request_moved_attributes.extend(
454
+ [
455
+ MovedAttribute("URLopener", "urllib", "urllib.request"),
456
+ MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
457
+ ]
458
+ )
454
459
  for attr in _urllib_request_moved_attributes:
455
460
  setattr(Module_six_moves_urllib_request, attr.name, attr)
456
461
  del attr
@@ -32,10 +32,6 @@ yumdnf_argument_spec = dict(
32
32
  enablerepo=dict(type='list', elements='str', default=[]),
33
33
  exclude=dict(type='list', elements='str', default=[]),
34
34
  installroot=dict(type='str', default="/"),
35
- install_repoquery=dict(
36
- type='bool', default=True,
37
- removed_in_version='2.20', removed_from_collection='ansible.builtin',
38
- ),
39
35
  install_weak_deps=dict(type='bool', default=True),
40
36
  list=dict(type='str'),
41
37
  name=dict(type='list', elements='str', aliases=['pkg'], default=[]),
@@ -85,7 +81,6 @@ class YumDnf(metaclass=ABCMeta):
85
81
  self.enablerepo = self.module.params.get('enablerepo', [])
86
82
  self.exclude = self.module.params['exclude']
87
83
  self.installroot = self.module.params['installroot']
88
- self.install_repoquery = self.module.params['install_repoquery']
89
84
  self.install_weak_deps = self.module.params['install_weak_deps']
90
85
  self.list = self.module.params['list']
91
86
  self.names = [p.strip() for p in self.module.params['name']]
ansible/modules/apt.py CHANGED
@@ -372,6 +372,7 @@ import locale as locale_module
372
372
  import os
373
373
  import re
374
374
  import secrets
375
+ import shlex
375
376
  import shutil
376
377
  import sys
377
378
  import tempfile
@@ -382,7 +383,6 @@ from ansible.module_utils.common.file import S_IRWXU_RXG_RXO
382
383
  from ansible.module_utils.common.locale import get_best_parsable_locale
383
384
  from ansible.module_utils.common.respawn import has_respawned, probe_interpreters_for_module, respawn_module
384
385
  from ansible.module_utils.common.text.converters import to_native, to_text
385
- from ansible.module_utils.six import string_types
386
386
  from ansible.module_utils.urls import fetch_file
387
387
 
388
388
  DPKG_OPTIONS = 'force-confdef,force-confold'
@@ -390,8 +390,6 @@ APT_GET_ZERO = "\n0 upgraded, 0 newly installed, 0 to remove"
390
390
  APTITUDE_ZERO = "\n0 packages upgraded, 0 newly installed, 0 to remove"
391
391
  APT_LISTS_PATH = "/var/lib/apt/lists"
392
392
  APT_UPDATE_SUCCESS_STAMP_PATH = "/var/lib/apt/periodic/update-success-stamp"
393
- APT_MARK_INVALID_OP = 'Invalid operation'
394
- APT_MARK_INVALID_OP_DEB6 = 'Usage: apt-mark [options] {markauto|unmarkauto} packages'
395
393
 
396
394
  CLEAN_OP_CHANGED_STR = dict(
397
395
  autoremove='The following packages will be REMOVED',
@@ -634,7 +632,7 @@ def expand_pkgspec_from_fnmatches(m, pkgspec, cache):
634
632
  if pkgspec:
635
633
  for pkgspec_pattern in pkgspec:
636
634
 
637
- if not isinstance(pkgspec_pattern, string_types):
635
+ if not isinstance(pkgspec_pattern, str):
638
636
  m.fail_json(msg="Invalid type for package name, expected string but got %s" % type(pkgspec_pattern))
639
637
 
640
638
  pkgname_pattern, version_cmp, version = package_split(pkgspec_pattern)
@@ -690,26 +688,30 @@ def parse_diff(output):
690
688
  return {'prepared': '\n'.join(diff[diff_start:diff_end])}
691
689
 
692
690
 
693
- def mark_installed_manually(m, packages):
691
+ def mark_installed(m: AnsibleModule, packages: list[str], manual: bool) -> None:
692
+ """Mark packages as manually or automatically installed."""
694
693
  if not packages:
695
694
  return
696
695
 
696
+ if manual:
697
+ mark_msg = "manually"
698
+ mark_op = "manual"
699
+ else:
700
+ mark_msg = "auto"
701
+ mark_op = "auto"
702
+
697
703
  apt_mark_cmd_path = m.get_bin_path("apt-mark")
698
704
 
699
705
  # https://github.com/ansible/ansible/issues/40531
700
706
  if apt_mark_cmd_path is None:
701
- m.warn("Could not find apt-mark binary, not marking package(s) as manually installed.")
707
+ m.warn(f"Could not find apt-mark binary, not marking package(s) as {mark_msg} installed.")
702
708
  return
703
709
 
704
- cmd = "%s manual %s" % (apt_mark_cmd_path, ' '.join(packages))
710
+ cmd = [apt_mark_cmd_path, mark_op] + packages
705
711
  rc, out, err = m.run_command(cmd)
706
712
 
707
- if APT_MARK_INVALID_OP in err or APT_MARK_INVALID_OP_DEB6 in err:
708
- cmd = "%s unmarkauto %s" % (apt_mark_cmd_path, ' '.join(packages))
709
- rc, out, err = m.run_command(cmd)
710
-
711
713
  if rc != 0:
712
- m.fail_json(msg="'%s' failed: %s" % (cmd, err), stdout=out, stderr=err, rc=rc)
714
+ m.fail_json(msg=f"Command {shlex.join(cmd)!r} failed.", stdout=out, stderr=err, rc=rc)
713
715
 
714
716
 
715
717
  def install(m, pkgspec, cache, upgrade=False, default_release=None,
@@ -835,7 +837,7 @@ def install(m, pkgspec, cache, upgrade=False, default_release=None,
835
837
  data = dict(changed=False)
836
838
 
837
839
  if not build_dep and not m.check_mode:
838
- mark_installed_manually(m, package_names)
840
+ mark_installed(m, package_names, manual=True)
839
841
 
840
842
  return (status, data)
841
843
 
@@ -914,6 +916,9 @@ def install_deb(
914
916
  dpkg_options=install_dpkg_options)
915
917
  if not success:
916
918
  m.fail_json(**retvals)
919
+ # Mark the dependencies as auto installed
920
+ # https://github.com/ansible/ansible/issues/78123
921
+ mark_installed(m, deps_to_install, manual=False)
917
922
  changed = retvals.get('changed', False)
918
923
 
919
924
  if pkgs_to_install:
@@ -508,7 +508,7 @@ class UbuntuSourcesList(SourcesList):
508
508
  try:
509
509
  rc, out, err = self.module.run_command([self.gpg_bin, '--list-packets', key_file])
510
510
  except OSError as ex:
511
- self.debug(f"Could check key against file {key_file!r}: {ex}")
511
+ self.module.debug(f"Could check key against file {key_file!r}: {ex}")
512
512
  continue
513
513
 
514
514
  if key_fingerprint in out:
@@ -131,7 +131,6 @@ import re
131
131
  import tempfile
132
132
 
133
133
  from ansible.module_utils.basic import AnsibleModule
134
- from ansible.module_utils.six import b, indexbytes
135
134
  from ansible.module_utils.common.text.converters import to_native
136
135
 
137
136
 
@@ -141,6 +140,7 @@ def assemble_from_fragments(src_path, delimiter=None, compiled_regexp=None, igno
141
140
  tmp = os.fdopen(tmpfd, 'wb')
142
141
  delimit_me = False
143
142
  add_newline = False
143
+ b_linesep = os.linesep.encode()
144
144
 
145
145
  for f in sorted(os.listdir(src_path)):
146
146
  if compiled_regexp and not compiled_regexp.search(f):
@@ -153,7 +153,7 @@ def assemble_from_fragments(src_path, delimiter=None, compiled_regexp=None, igno
153
153
 
154
154
  # always put a newline between fragments if the previous fragment didn't end with a newline.
155
155
  if add_newline:
156
- tmp.write(b('\n'))
156
+ tmp.write(b_linesep)
157
157
 
158
158
  # delimiters should only appear between fragments
159
159
  if delimit_me:
@@ -163,16 +163,12 @@ def assemble_from_fragments(src_path, delimiter=None, compiled_regexp=None, igno
163
163
  tmp.write(delimiter)
164
164
  # always make sure there's a newline after the
165
165
  # delimiter, so lines don't run together
166
-
167
- # byte indexing differs on Python 2 and 3,
168
- # use indexbytes for compat
169
- # chr(10) == '\n'
170
- if indexbytes(delimiter, -1) != 10:
171
- tmp.write(b('\n'))
166
+ if not delimiter.endswith(b_linesep):
167
+ tmp.write(b_linesep)
172
168
 
173
169
  tmp.write(fragment_content)
174
170
  delimit_me = True
175
- if fragment_content.endswith(b('\n')):
171
+ if fragment_content.endswith(b_linesep):
176
172
  add_newline = False
177
173
  else:
178
174
  add_newline = True
@@ -102,6 +102,13 @@ options:
102
102
  type: bool
103
103
  default: no
104
104
  version_added: '2.16'
105
+ encoding:
106
+ description:
107
+ - The character set in which the target file is encoded.
108
+ - For a list of available built-in encodings, see U(https://docs.python.org/3/library/codecs.html#standard-encodings)
109
+ type: str
110
+ default: utf-8
111
+ version_added: '2.20'
105
112
  notes:
106
113
  - When using C(with_*) loops be aware that if you do not set a unique mark the block will be overwritten on each iteration.
107
114
  - As of Ansible 2.3, the O(dest) option has been changed to O(path) as default, but O(dest) still works as well.
@@ -192,15 +199,16 @@ EXAMPLES = r"""
192
199
  import re
193
200
  import os
194
201
  import tempfile
195
- from ansible.module_utils.six import b
202
+
196
203
  from ansible.module_utils.basic import AnsibleModule
197
- from ansible.module_utils.common.text.converters import to_bytes, to_native
204
+ from ansible.module_utils.common.text.converters import to_native
198
205
 
199
206
 
200
- def write_changes(module, contents, path):
207
+ def write_changes(module, contents, path, encoding=None):
201
208
 
202
209
  tmpfd, tmpfile = tempfile.mkstemp(dir=module.tmpdir)
203
- with os.fdopen(tmpfd, 'wb') as tf:
210
+ # newline param set to translate newline sequences with system default line separator
211
+ with os.fdopen(tmpfd, 'w', encoding=encoding, newline=None) as tf:
204
212
  tf.write(contents)
205
213
 
206
214
  validate = module.params.get('validate', None)
@@ -246,6 +254,7 @@ def main():
246
254
  marker_end=dict(type='str', default='END'),
247
255
  append_newline=dict(type='bool', default=False),
248
256
  prepend_newline=dict(type='bool', default=False),
257
+ encoding=dict(type='str', default='utf-8'),
249
258
  ),
250
259
  mutually_exclusive=[['insertbefore', 'insertafter']],
251
260
  add_file_common_args=True,
@@ -254,6 +263,8 @@ def main():
254
263
  params = module.params
255
264
  path = params['path']
256
265
 
266
+ encoding = module.params.get('encoding', None)
267
+
257
268
  if os.path.isdir(path):
258
269
  module.fail_json(rc=256,
259
270
  msg='Path %s is a directory !' % path)
@@ -274,7 +285,8 @@ def main():
274
285
  original = None
275
286
  lines = []
276
287
  else:
277
- with open(path, 'rb') as f:
288
+ # newline param set to preserve newline sequences read from file
289
+ with open(path, 'r', encoding=encoding, newline='') as f:
278
290
  original = f.read()
279
291
  lines = original.splitlines(True)
280
292
 
@@ -288,10 +300,12 @@ def main():
288
300
 
289
301
  insertbefore = params['insertbefore']
290
302
  insertafter = params['insertafter']
291
- block = to_bytes(params['block'])
292
- marker = to_bytes(params['marker'])
303
+ block = params['block']
304
+ marker = params['marker']
293
305
  present = params['state'] == 'present'
294
- blank_line = [b(os.linesep)]
306
+
307
+ line_separator = os.linesep
308
+ blank_line = [line_separator]
295
309
 
296
310
  if not present and not path_exists:
297
311
  module.exit_json(changed=False, msg="File %s not present" % path)
@@ -300,17 +314,19 @@ def main():
300
314
  insertafter = 'EOF'
301
315
 
302
316
  if insertafter not in (None, 'EOF'):
303
- insertre = re.compile(to_bytes(insertafter, errors='surrogate_or_strict'))
317
+ insertre = re.compile(insertafter)
304
318
  elif insertbefore not in (None, 'BOF'):
305
- insertre = re.compile(to_bytes(insertbefore, errors='surrogate_or_strict'))
319
+ insertre = re.compile(insertbefore)
306
320
  else:
307
321
  insertre = None
308
322
 
309
- marker0 = re.sub(b(r'{mark}'), b(params['marker_begin']), marker) + b(os.linesep)
310
- marker1 = re.sub(b(r'{mark}'), b(params['marker_end']), marker) + b(os.linesep)
323
+ marker0 = re.sub(r'{mark}', params['marker_begin'], marker) + line_separator
324
+ marker1 = re.sub(r'{mark}', params['marker_end'], marker) + line_separator
325
+
311
326
  if present and block:
312
- if not block.endswith(b(os.linesep)):
313
- block += b(os.linesep)
327
+ if not block.endswith(line_separator):
328
+ block += line_separator
329
+
314
330
  blocklines = [marker0] + block.splitlines(True) + [marker1]
315
331
  else:
316
332
  blocklines = []
@@ -329,9 +345,9 @@ def main():
329
345
  match = insertre.search(original)
330
346
  if match:
331
347
  if insertafter:
332
- n0 = to_native(original).count('\n', 0, match.end())
348
+ n0 = original.count('\n', 0, match.end())
333
349
  elif insertbefore:
334
- n0 = to_native(original).count('\n', 0, match.start())
350
+ n0 = original.count('\n', 0, match.start())
335
351
  else:
336
352
  for i, line in enumerate(lines):
337
353
  if insertre.search(line):
@@ -352,15 +368,15 @@ def main():
352
368
 
353
369
  # Ensure there is a line separator before the block of lines to be inserted
354
370
  if n0 > 0:
355
- if not lines[n0 - 1].endswith(b(os.linesep)):
356
- lines[n0 - 1] += b(os.linesep)
371
+ if not lines[n0 - 1].endswith(line_separator):
372
+ lines[n0 - 1] += line_separator
357
373
 
358
374
  # Before the block: check if we need to prepend a blank line
359
375
  # If yes, we need to add the blank line if we are not at the beginning of the file
360
376
  # and the previous line is not a blank line
361
377
  # In both cases, we need to shift by one on the right the inserting position of the block
362
378
  if params['prepend_newline'] and present:
363
- if n0 != 0 and lines[n0 - 1] != b(os.linesep):
379
+ if n0 != 0 and lines[n0 - 1] != line_separator:
364
380
  lines[n0:n0] = blank_line
365
381
  n0 += 1
366
382
 
@@ -372,13 +388,13 @@ def main():
372
388
  # and the line right after is not a blank line
373
389
  if params['append_newline'] and present:
374
390
  line_after_block = n0 + len(blocklines)
375
- if line_after_block < len(lines) and lines[line_after_block] != b(os.linesep):
391
+ if line_after_block < len(lines) and lines[line_after_block] != line_separator:
376
392
  lines[line_after_block:line_after_block] = blank_line
377
393
 
378
394
  if lines:
379
- result = b''.join(lines)
395
+ result = ''.join(lines)
380
396
  else:
381
- result = b''
397
+ result = ''
382
398
 
383
399
  if module._diff:
384
400
  diff['after'] = result
@@ -402,7 +418,7 @@ def main():
402
418
  backup_file = module.backup_local(path)
403
419
  # We should always follow symlinks so that we change the real file
404
420
  real_path = os.path.realpath(params['path'])
405
- write_changes(module, result, real_path)
421
+ write_changes(module, result, real_path, encoding)
406
422
 
407
423
  if module.check_mode and not path_exists:
408
424
  module.exit_json(changed=changed, msg=msg, diff=diff)