ansible-core 2.16.5__py3-none-any.whl → 2.17.0b1__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 (597) hide show
  1. ansible/__init__.py +1 -3
  2. ansible/__main__.py +1 -0
  3. ansible/_vendor/__init__.py +1 -2
  4. ansible/cli/__init__.py +7 -8
  5. ansible/cli/adhoc.py +1 -2
  6. ansible/cli/arguments/__init__.py +1 -2
  7. ansible/cli/arguments/option_helpers.py +1 -2
  8. ansible/cli/config.py +1 -2
  9. ansible/cli/console.py +1 -2
  10. ansible/cli/doc.py +320 -198
  11. ansible/cli/galaxy.py +9 -3
  12. ansible/cli/inventory.py +5 -27
  13. ansible/cli/playbook.py +1 -2
  14. ansible/cli/pull.py +4 -5
  15. ansible/cli/scripts/ansible_connection_cli_stub.py +1 -4
  16. ansible/cli/vault.py +1 -2
  17. ansible/collections/list.py +1 -0
  18. ansible/compat/__init__.py +1 -4
  19. ansible/compat/importlib_resources.py +1 -2
  20. ansible/compat/{selectors/__init__.py → selectors.py} +12 -12
  21. ansible/config/ansible_builtin_runtime.yml +2 -0
  22. ansible/config/base.yml +154 -149
  23. ansible/config/manager.py +32 -25
  24. ansible/constants.py +41 -2
  25. ansible/context.py +1 -4
  26. ansible/errors/__init__.py +1 -3
  27. ansible/errors/yaml_strings.py +1 -3
  28. ansible/executor/__init__.py +1 -3
  29. ansible/executor/discovery/python_target.py +1 -2
  30. ansible/executor/interpreter_discovery.py +9 -8
  31. ansible/executor/module_common.py +1 -3
  32. ansible/executor/play_iterator.py +1 -3
  33. ansible/executor/playbook_executor.py +1 -3
  34. ansible/executor/powershell/module_manifest.py +2 -3
  35. ansible/executor/process/__init__.py +1 -3
  36. ansible/executor/process/worker.py +1 -3
  37. ansible/executor/stats.py +1 -3
  38. ansible/executor/task_executor.py +10 -5
  39. ansible/executor/task_queue_manager.py +1 -3
  40. ansible/executor/task_result.py +2 -3
  41. ansible/galaxy/__init__.py +1 -2
  42. ansible/galaxy/api.py +10 -2
  43. ansible/galaxy/collection/__init__.py +38 -24
  44. ansible/galaxy/collection/concrete_artifact_manager.py +1 -2
  45. ansible/galaxy/collection/galaxy_api_proxy.py +1 -2
  46. ansible/galaxy/collection/gpg.py +4 -2
  47. ansible/galaxy/data/apb/meta/main.yml.j2 +0 -15
  48. ansible/galaxy/data/container/meta/main.yml.j2 +0 -18
  49. ansible/galaxy/data/default/role/meta/main.yml.j2 +0 -18
  50. ansible/galaxy/data/network/cliconf_plugins/example.py.j2 +1 -2
  51. ansible/galaxy/data/network/library/example_command.py.j2 +1 -2
  52. ansible/galaxy/data/network/library/example_config.py.j2 +1 -2
  53. ansible/galaxy/data/network/library/example_facts.py.j2 +1 -2
  54. ansible/galaxy/data/network/meta/main.yml.j2 +0 -15
  55. ansible/galaxy/data/network/module_utils/example.py.j2 +1 -2
  56. ansible/galaxy/data/network/netconf_plugins/example.py.j2 +1 -2
  57. ansible/galaxy/data/network/terminal_plugins/example.py.j2 +1 -2
  58. ansible/galaxy/dependency_resolution/__init__.py +1 -2
  59. ansible/galaxy/dependency_resolution/dataclasses.py +5 -6
  60. ansible/galaxy/dependency_resolution/errors.py +1 -2
  61. ansible/galaxy/dependency_resolution/providers.py +3 -4
  62. ansible/galaxy/dependency_resolution/reporters.py +2 -3
  63. ansible/galaxy/dependency_resolution/resolvers.py +1 -2
  64. ansible/galaxy/dependency_resolution/versioning.py +1 -2
  65. ansible/galaxy/role.py +2 -3
  66. ansible/galaxy/token.py +1 -2
  67. ansible/galaxy/user_agent.py +1 -2
  68. ansible/inventory/data.py +1 -2
  69. ansible/inventory/group.py +1 -2
  70. ansible/inventory/helpers.py +1 -2
  71. ansible/inventory/host.py +1 -3
  72. ansible/inventory/manager.py +1 -2
  73. ansible/module_utils/_text.py +1 -2
  74. ansible/module_utils/ansible_release.py +3 -5
  75. ansible/module_utils/api.py +1 -2
  76. ansible/module_utils/basic.py +113 -158
  77. ansible/module_utils/common/_collections_compat.py +1 -2
  78. ansible/module_utils/common/_utils.py +1 -3
  79. ansible/module_utils/common/arg_spec.py +1 -2
  80. ansible/module_utils/common/collections.py +1 -2
  81. ansible/module_utils/common/dict_transformations.py +1 -2
  82. ansible/module_utils/common/file.py +10 -5
  83. ansible/module_utils/common/json.py +1 -3
  84. ansible/module_utils/common/locale.py +1 -2
  85. ansible/module_utils/common/network.py +2 -3
  86. ansible/module_utils/common/parameters.py +9 -9
  87. ansible/module_utils/common/process.py +12 -5
  88. ansible/module_utils/common/respawn.py +2 -3
  89. ansible/module_utils/common/sys_info.py +1 -2
  90. ansible/module_utils/common/text/converters.py +1 -2
  91. ansible/module_utils/common/text/formatters.py +1 -2
  92. ansible/module_utils/common/validation.py +5 -6
  93. ansible/module_utils/common/warnings.py +1 -2
  94. ansible/module_utils/common/yaml.py +1 -2
  95. ansible/module_utils/compat/datetime.py +1 -3
  96. ansible/module_utils/compat/importlib.py +21 -13
  97. ansible/module_utils/compat/paramiko.py +1 -2
  98. ansible/module_utils/compat/selectors.py +10 -34
  99. ansible/module_utils/compat/selinux.py +1 -2
  100. ansible/module_utils/compat/typing.py +1 -2
  101. ansible/module_utils/compat/version.py +1 -2
  102. ansible/module_utils/connection.py +1 -2
  103. ansible/module_utils/csharp/Ansible.Basic.cs +20 -3
  104. ansible/module_utils/distro/__init__.py +2 -3
  105. ansible/module_utils/distro/_distro.py +230 -234
  106. ansible/module_utils/errors.py +1 -2
  107. ansible/module_utils/facts/__init__.py +1 -2
  108. ansible/module_utils/facts/ansible_collector.py +1 -2
  109. ansible/module_utils/facts/collector.py +1 -2
  110. ansible/module_utils/facts/compat.py +1 -2
  111. ansible/module_utils/facts/default_collectors.py +1 -2
  112. ansible/module_utils/facts/hardware/aix.py +1 -2
  113. ansible/module_utils/facts/hardware/base.py +1 -2
  114. ansible/module_utils/facts/hardware/darwin.py +1 -2
  115. ansible/module_utils/facts/hardware/dragonfly.py +1 -2
  116. ansible/module_utils/facts/hardware/freebsd.py +1 -2
  117. ansible/module_utils/facts/hardware/hpux.py +1 -2
  118. ansible/module_utils/facts/hardware/hurd.py +1 -2
  119. ansible/module_utils/facts/hardware/linux.py +8 -6
  120. ansible/module_utils/facts/hardware/netbsd.py +1 -2
  121. ansible/module_utils/facts/hardware/openbsd.py +1 -2
  122. ansible/module_utils/facts/hardware/sunos.py +2 -3
  123. ansible/module_utils/facts/namespace.py +1 -2
  124. ansible/module_utils/facts/network/aix.py +1 -2
  125. ansible/module_utils/facts/network/base.py +1 -2
  126. ansible/module_utils/facts/network/darwin.py +1 -2
  127. ansible/module_utils/facts/network/dragonfly.py +1 -2
  128. ansible/module_utils/facts/network/fc_wwn.py +1 -2
  129. ansible/module_utils/facts/network/freebsd.py +1 -2
  130. ansible/module_utils/facts/network/generic_bsd.py +1 -2
  131. ansible/module_utils/facts/network/hpux.py +1 -2
  132. ansible/module_utils/facts/network/hurd.py +1 -2
  133. ansible/module_utils/facts/network/iscsi.py +1 -2
  134. ansible/module_utils/facts/network/linux.py +1 -2
  135. ansible/module_utils/facts/network/netbsd.py +1 -2
  136. ansible/module_utils/facts/network/nvme.py +1 -2
  137. ansible/module_utils/facts/network/openbsd.py +1 -2
  138. ansible/module_utils/facts/network/sunos.py +1 -2
  139. ansible/module_utils/facts/other/facter.py +1 -2
  140. ansible/module_utils/facts/other/ohai.py +1 -2
  141. ansible/module_utils/facts/packages.py +1 -2
  142. ansible/module_utils/facts/sysctl.py +1 -2
  143. ansible/module_utils/facts/system/apparmor.py +1 -2
  144. ansible/module_utils/facts/system/caps.py +1 -2
  145. ansible/module_utils/facts/system/chroot.py +1 -2
  146. ansible/module_utils/facts/system/cmdline.py +1 -2
  147. ansible/module_utils/facts/system/date_time.py +1 -2
  148. ansible/module_utils/facts/system/distribution.py +4 -5
  149. ansible/module_utils/facts/system/dns.py +1 -2
  150. ansible/module_utils/facts/system/env.py +1 -2
  151. ansible/module_utils/facts/system/fips.py +1 -2
  152. ansible/module_utils/facts/system/loadavg.py +1 -2
  153. ansible/module_utils/facts/system/local.py +1 -2
  154. ansible/module_utils/facts/system/lsb.py +1 -2
  155. ansible/module_utils/facts/system/pkg_mgr.py +7 -30
  156. ansible/module_utils/facts/system/platform.py +1 -2
  157. ansible/module_utils/facts/system/python.py +1 -2
  158. ansible/module_utils/facts/system/selinux.py +1 -2
  159. ansible/module_utils/facts/system/service_mgr.py +1 -2
  160. ansible/module_utils/facts/system/ssh_pub_keys.py +1 -2
  161. ansible/module_utils/facts/system/user.py +1 -2
  162. ansible/module_utils/facts/timeout.py +1 -2
  163. ansible/module_utils/facts/utils.py +1 -2
  164. ansible/module_utils/facts/virtual/base.py +1 -2
  165. ansible/module_utils/facts/virtual/dragonfly.py +1 -2
  166. ansible/module_utils/facts/virtual/freebsd.py +1 -2
  167. ansible/module_utils/facts/virtual/hpux.py +1 -2
  168. ansible/module_utils/facts/virtual/linux.py +2 -3
  169. ansible/module_utils/facts/virtual/netbsd.py +1 -2
  170. ansible/module_utils/facts/virtual/openbsd.py +1 -2
  171. ansible/module_utils/facts/virtual/sunos.py +1 -2
  172. ansible/module_utils/facts/virtual/sysctl.py +1 -2
  173. ansible/module_utils/json_utils.py +1 -2
  174. ansible/module_utils/parsing/convert_bool.py +1 -2
  175. ansible/module_utils/powershell/Ansible.ModuleUtils.Legacy.psm1 +5 -2
  176. ansible/module_utils/powershell/Ansible.ModuleUtils.WebRequest.psm1 +1 -1
  177. ansible/module_utils/pycompat24.py +24 -4
  178. ansible/module_utils/service.py +31 -5
  179. ansible/module_utils/six/__init__.py +1 -1
  180. ansible/module_utils/splitter.py +1 -2
  181. ansible/module_utils/urls.py +335 -1052
  182. ansible/module_utils/yumdnf.py +13 -35
  183. ansible/modules/add_host.py +1 -2
  184. ansible/modules/apt.py +38 -22
  185. ansible/modules/apt_key.py +1 -2
  186. ansible/modules/apt_repository.py +18 -10
  187. ansible/modules/assemble.py +1 -2
  188. ansible/modules/assert.py +8 -4
  189. ansible/modules/async_status.py +17 -14
  190. ansible/modules/async_wrapper.py +11 -9
  191. ansible/modules/blockinfile.py +3 -4
  192. ansible/modules/command.py +1 -2
  193. ansible/modules/copy.py +4 -76
  194. ansible/modules/cron.py +3 -3
  195. ansible/modules/deb822_repository.py +5 -5
  196. ansible/modules/debconf.py +19 -8
  197. ansible/modules/debug.py +1 -2
  198. ansible/modules/dnf.py +63 -188
  199. ansible/modules/dnf5.py +57 -43
  200. ansible/modules/dpkg_selections.py +1 -2
  201. ansible/modules/expect.py +23 -15
  202. ansible/modules/fail.py +1 -2
  203. ansible/modules/fetch.py +1 -2
  204. ansible/modules/file.py +4 -3
  205. ansible/modules/find.py +25 -9
  206. ansible/modules/gather_facts.py +1 -2
  207. ansible/modules/get_url.py +2 -3
  208. ansible/modules/getent.py +2 -3
  209. ansible/modules/git.py +28 -17
  210. ansible/modules/group.py +1 -2
  211. ansible/modules/group_by.py +1 -2
  212. ansible/modules/hostname.py +2 -19
  213. ansible/modules/import_playbook.py +1 -2
  214. ansible/modules/import_role.py +9 -2
  215. ansible/modules/import_tasks.py +1 -2
  216. ansible/modules/include_role.py +1 -2
  217. ansible/modules/include_tasks.py +1 -2
  218. ansible/modules/include_vars.py +1 -2
  219. ansible/modules/iptables.py +38 -21
  220. ansible/modules/known_hosts.py +15 -8
  221. ansible/modules/lineinfile.py +1 -6
  222. ansible/modules/meta.py +3 -2
  223. ansible/modules/package.py +6 -5
  224. ansible/modules/package_facts.py +1 -2
  225. ansible/modules/pause.py +2 -3
  226. ansible/modules/ping.py +1 -2
  227. ansible/modules/pip.py +40 -20
  228. ansible/modules/raw.py +1 -2
  229. ansible/modules/reboot.py +1 -2
  230. ansible/modules/replace.py +7 -5
  231. ansible/modules/rpm_key.py +1 -2
  232. ansible/modules/script.py +1 -2
  233. ansible/modules/service.py +3 -21
  234. ansible/modules/service_facts.py +3 -12
  235. ansible/modules/set_fact.py +1 -2
  236. ansible/modules/set_stats.py +1 -2
  237. ansible/modules/setup.py +1 -2
  238. ansible/modules/shell.py +1 -2
  239. ansible/modules/slurp.py +1 -2
  240. ansible/modules/stat.py +1 -2
  241. ansible/modules/subversion.py +2 -3
  242. ansible/modules/systemd.py +12 -9
  243. ansible/modules/systemd_service.py +12 -9
  244. ansible/modules/sysvinit.py +7 -2
  245. ansible/modules/tempfile.py +7 -2
  246. ansible/modules/template.py +2 -3
  247. ansible/modules/unarchive.py +14 -4
  248. ansible/modules/uri.py +5 -8
  249. ansible/modules/user.py +11 -10
  250. ansible/modules/validate_argument_spec.py +15 -16
  251. ansible/modules/wait_for.py +1 -2
  252. ansible/modules/wait_for_connection.py +1 -2
  253. ansible/modules/yum_repository.py +2 -3
  254. ansible/parsing/__init__.py +1 -3
  255. ansible/parsing/ajson.py +1 -3
  256. ansible/parsing/dataloader.py +23 -12
  257. ansible/parsing/mod_args.py +14 -8
  258. ansible/parsing/plugin_docs.py +1 -2
  259. ansible/parsing/quoting.py +1 -3
  260. ansible/parsing/splitter.py +1 -3
  261. ansible/parsing/utils/__init__.py +1 -3
  262. ansible/parsing/utils/addresses.py +1 -3
  263. ansible/parsing/utils/jsonify.py +1 -3
  264. ansible/parsing/utils/yaml.py +1 -3
  265. ansible/parsing/vault/__init__.py +6 -8
  266. ansible/parsing/yaml/__init__.py +1 -3
  267. ansible/parsing/yaml/constructor.py +1 -3
  268. ansible/parsing/yaml/dumper.py +1 -3
  269. ansible/parsing/yaml/loader.py +1 -3
  270. ansible/parsing/yaml/objects.py +1 -3
  271. ansible/playbook/__init__.py +1 -3
  272. ansible/playbook/attribute.py +1 -3
  273. ansible/playbook/base.py +2 -3
  274. ansible/playbook/block.py +1 -3
  275. ansible/playbook/collectionsearch.py +1 -2
  276. ansible/playbook/conditional.py +1 -3
  277. ansible/playbook/delegatable.py +1 -0
  278. ansible/playbook/handler.py +2 -4
  279. ansible/playbook/handler_task_include.py +1 -3
  280. ansible/playbook/helpers.py +1 -4
  281. ansible/playbook/included_file.py +4 -4
  282. ansible/playbook/loop_control.py +1 -3
  283. ansible/playbook/notifiable.py +1 -0
  284. ansible/playbook/play.py +1 -3
  285. ansible/playbook/play_context.py +1 -3
  286. ansible/playbook/playbook_include.py +1 -3
  287. ansible/playbook/role/__init__.py +2 -4
  288. ansible/playbook/role/definition.py +1 -3
  289. ansible/playbook/role/include.py +1 -3
  290. ansible/playbook/role/metadata.py +1 -3
  291. ansible/playbook/role/requirement.py +1 -3
  292. ansible/playbook/role_include.py +2 -10
  293. ansible/playbook/taggable.py +1 -3
  294. ansible/playbook/task.py +2 -4
  295. ansible/playbook/task_include.py +1 -3
  296. ansible/plugins/__init__.py +4 -5
  297. ansible/plugins/action/__init__.py +20 -14
  298. ansible/plugins/action/add_host.py +2 -4
  299. ansible/plugins/action/assemble.py +2 -3
  300. ansible/plugins/action/assert.py +1 -2
  301. ansible/plugins/action/async_status.py +1 -2
  302. ansible/plugins/action/command.py +1 -2
  303. ansible/plugins/action/copy.py +12 -9
  304. ansible/plugins/action/debug.py +1 -2
  305. ansible/plugins/action/dnf.py +4 -4
  306. ansible/plugins/action/fail.py +1 -2
  307. ansible/plugins/action/fetch.py +6 -3
  308. ansible/plugins/action/gather_facts.py +3 -4
  309. ansible/plugins/action/group_by.py +1 -2
  310. ansible/plugins/action/include_vars.py +1 -2
  311. ansible/plugins/action/normal.py +1 -2
  312. ansible/plugins/action/package.py +36 -21
  313. ansible/plugins/action/pause.py +1 -2
  314. ansible/plugins/action/raw.py +2 -3
  315. ansible/plugins/action/reboot.py +30 -15
  316. ansible/plugins/action/script.py +3 -4
  317. ansible/plugins/action/service.py +1 -2
  318. ansible/plugins/action/set_fact.py +1 -2
  319. ansible/plugins/action/set_stats.py +1 -2
  320. ansible/plugins/action/shell.py +1 -2
  321. ansible/plugins/action/template.py +1 -2
  322. ansible/plugins/action/unarchive.py +1 -2
  323. ansible/plugins/action/uri.py +2 -3
  324. ansible/plugins/action/validate_argument_spec.py +1 -2
  325. ansible/plugins/action/wait_for_connection.py +2 -3
  326. ansible/plugins/become/__init__.py +1 -2
  327. ansible/plugins/become/runas.py +1 -2
  328. ansible/plugins/become/su.py +1 -2
  329. ansible/plugins/become/sudo.py +1 -2
  330. ansible/plugins/cache/__init__.py +3 -2
  331. ansible/plugins/cache/base.py +1 -2
  332. ansible/plugins/cache/jsonfile.py +1 -3
  333. ansible/plugins/cache/memory.py +1 -2
  334. ansible/plugins/callback/__init__.py +2 -4
  335. ansible/plugins/callback/default.py +2 -3
  336. ansible/plugins/callback/junit.py +1 -2
  337. ansible/plugins/callback/minimal.py +1 -3
  338. ansible/plugins/callback/oneline.py +1 -3
  339. ansible/plugins/callback/tree.py +1 -2
  340. ansible/plugins/cliconf/__init__.py +1 -2
  341. ansible/plugins/connection/__init__.py +4 -5
  342. ansible/plugins/connection/local.py +3 -4
  343. ansible/plugins/connection/paramiko_ssh.py +1 -2
  344. ansible/plugins/connection/psrp.py +1 -2
  345. ansible/plugins/connection/ssh.py +18 -54
  346. ansible/plugins/connection/winrm.py +17 -6
  347. ansible/plugins/doc_fragments/action_common_attributes.py +2 -3
  348. ansible/plugins/doc_fragments/action_core.py +3 -4
  349. ansible/plugins/doc_fragments/backup.py +1 -2
  350. ansible/plugins/doc_fragments/connection_pipelining.py +1 -2
  351. ansible/plugins/doc_fragments/constructed.py +1 -2
  352. ansible/plugins/doc_fragments/decrypt.py +2 -3
  353. ansible/plugins/doc_fragments/default_callback.py +1 -2
  354. ansible/plugins/doc_fragments/files.py +1 -2
  355. ansible/plugins/doc_fragments/inventory_cache.py +1 -2
  356. ansible/plugins/doc_fragments/result_format_callback.py +1 -2
  357. ansible/plugins/doc_fragments/return_common.py +1 -2
  358. ansible/plugins/doc_fragments/shell_common.py +1 -2
  359. ansible/plugins/doc_fragments/shell_windows.py +1 -2
  360. ansible/plugins/doc_fragments/template_common.py +1 -2
  361. ansible/plugins/doc_fragments/url.py +1 -2
  362. ansible/plugins/doc_fragments/url_windows.py +1 -2
  363. ansible/plugins/doc_fragments/validate.py +1 -2
  364. ansible/plugins/doc_fragments/vars_plugin_staging.py +1 -2
  365. ansible/plugins/filter/__init__.py +1 -2
  366. ansible/plugins/filter/b64decode.yml +8 -8
  367. ansible/plugins/filter/b64encode.yml +4 -4
  368. ansible/plugins/filter/comment.yml +1 -1
  369. ansible/plugins/filter/core.py +11 -9
  370. ansible/plugins/filter/encryption.py +1 -3
  371. ansible/plugins/filter/extract.yml +1 -1
  372. ansible/plugins/filter/from_yaml_all.yml +1 -1
  373. ansible/plugins/filter/human_readable.yml +3 -3
  374. ansible/plugins/filter/human_to_bytes.yml +2 -2
  375. ansible/plugins/filter/mandatory.yml +1 -1
  376. ansible/plugins/filter/mathstuff.py +2 -2
  377. ansible/plugins/filter/password_hash.yml +3 -2
  378. ansible/plugins/filter/regex_replace.yml +15 -0
  379. ansible/plugins/filter/regex_search.yml +12 -0
  380. ansible/plugins/filter/strftime.yml +2 -9
  381. ansible/plugins/filter/to_datetime.yml +17 -2
  382. ansible/plugins/filter/to_nice_json.yml +4 -0
  383. ansible/plugins/filter/union.yml +1 -1
  384. ansible/plugins/filter/urls.py +1 -2
  385. ansible/plugins/filter/urlsplit.py +1 -2
  386. ansible/plugins/filter/zip.yml +2 -2
  387. ansible/plugins/filter/zip_longest.yml +1 -1
  388. ansible/plugins/httpapi/__init__.py +1 -2
  389. ansible/plugins/inventory/__init__.py +2 -4
  390. ansible/plugins/inventory/advanced_host_list.py +1 -2
  391. ansible/plugins/inventory/auto.py +2 -3
  392. ansible/plugins/inventory/constructed.py +3 -2
  393. ansible/plugins/inventory/generator.py +1 -2
  394. ansible/plugins/inventory/host_list.py +1 -2
  395. ansible/plugins/inventory/ini.py +1 -2
  396. ansible/plugins/inventory/script.py +122 -3
  397. ansible/plugins/inventory/toml.py +1 -2
  398. ansible/plugins/inventory/yaml.py +3 -4
  399. ansible/plugins/list.py +2 -3
  400. ansible/plugins/loader.py +10 -11
  401. ansible/plugins/lookup/__init__.py +1 -3
  402. ansible/plugins/lookup/config.py +19 -15
  403. ansible/plugins/lookup/csvfile.py +16 -7
  404. ansible/plugins/lookup/dict.py +2 -3
  405. ansible/plugins/lookup/env.py +4 -4
  406. ansible/plugins/lookup/file.py +1 -2
  407. ansible/plugins/lookup/fileglob.py +1 -2
  408. ansible/plugins/lookup/first_found.py +8 -7
  409. ansible/plugins/lookup/indexed_items.py +1 -2
  410. ansible/plugins/lookup/ini.py +6 -3
  411. ansible/plugins/lookup/inventory_hostnames.py +1 -2
  412. ansible/plugins/lookup/items.py +1 -2
  413. ansible/plugins/lookup/lines.py +1 -2
  414. ansible/plugins/lookup/list.py +1 -3
  415. ansible/plugins/lookup/nested.py +1 -2
  416. ansible/plugins/lookup/password.py +16 -14
  417. ansible/plugins/lookup/pipe.py +1 -2
  418. ansible/plugins/lookup/random_choice.py +1 -2
  419. ansible/plugins/lookup/sequence.py +21 -52
  420. ansible/plugins/lookup/subelements.py +1 -2
  421. ansible/plugins/lookup/template.py +1 -2
  422. ansible/plugins/lookup/together.py +1 -2
  423. ansible/plugins/lookup/unvault.py +1 -2
  424. ansible/plugins/lookup/url.py +9 -3
  425. ansible/plugins/lookup/varnames.py +1 -2
  426. ansible/plugins/lookup/vars.py +1 -2
  427. ansible/plugins/netconf/__init__.py +1 -2
  428. ansible/plugins/shell/__init__.py +3 -4
  429. ansible/plugins/shell/cmd.py +1 -2
  430. ansible/plugins/shell/powershell.py +1 -2
  431. ansible/plugins/shell/sh.py +1 -2
  432. ansible/plugins/strategy/__init__.py +33 -21
  433. ansible/plugins/strategy/debug.py +1 -2
  434. ansible/plugins/strategy/free.py +18 -8
  435. ansible/plugins/strategy/host_pinned.py +1 -3
  436. ansible/plugins/strategy/linear.py +23 -23
  437. ansible/plugins/terminal/__init__.py +2 -3
  438. ansible/plugins/test/__init__.py +1 -2
  439. ansible/plugins/test/change.yml +1 -1
  440. ansible/plugins/test/changed.yml +1 -1
  441. ansible/plugins/test/contains.yml +1 -1
  442. ansible/plugins/test/core.py +2 -4
  443. ansible/plugins/test/exists.yml +1 -1
  444. ansible/plugins/test/failed.yml +1 -1
  445. ansible/plugins/test/failure.yml +1 -1
  446. ansible/plugins/test/files.py +1 -3
  447. ansible/plugins/test/finished.yml +3 -3
  448. ansible/plugins/test/issuperset.yml +1 -1
  449. ansible/plugins/test/match.yml +1 -1
  450. ansible/plugins/test/mathstuff.py +1 -2
  451. ansible/plugins/test/reachable.yml +1 -1
  452. ansible/plugins/test/regex.yml +1 -1
  453. ansible/plugins/test/search.yml +1 -1
  454. ansible/plugins/test/skip.yml +1 -1
  455. ansible/plugins/test/skipped.yml +1 -1
  456. ansible/plugins/test/started.yml +1 -1
  457. ansible/plugins/test/succeeded.yml +1 -1
  458. ansible/plugins/test/success.yml +1 -1
  459. ansible/plugins/test/successful.yml +1 -1
  460. ansible/plugins/test/superset.yml +1 -1
  461. ansible/plugins/test/unreachable.yml +1 -1
  462. ansible/plugins/test/uri.py +1 -3
  463. ansible/plugins/vars/__init__.py +1 -2
  464. ansible/plugins/vars/host_group_vars.py +2 -3
  465. ansible/release.py +3 -5
  466. ansible/template/__init__.py +14 -27
  467. ansible/template/native_helpers.py +1 -3
  468. ansible/template/template.py +1 -3
  469. ansible/template/vars.py +1 -0
  470. ansible/utils/__init__.py +1 -3
  471. ansible/utils/cmd_functions.py +1 -2
  472. ansible/utils/collection_loader/__init__.py +1 -2
  473. ansible/utils/collection_loader/_collection_config.py +1 -2
  474. ansible/utils/collection_loader/_collection_finder.py +1 -2
  475. ansible/utils/collection_loader/_collection_meta.py +1 -2
  476. ansible/utils/color.py +1 -2
  477. ansible/utils/context_objects.py +1 -4
  478. ansible/utils/display.py +88 -30
  479. ansible/utils/encrypt.py +4 -105
  480. ansible/utils/fqcn.py +1 -2
  481. ansible/utils/galaxy.py +1 -3
  482. ansible/utils/hashing.py +1 -3
  483. ansible/utils/helpers.py +1 -3
  484. ansible/utils/jsonrpc.py +1 -2
  485. ansible/utils/listify.py +1 -3
  486. ansible/utils/lock.py +1 -3
  487. ansible/utils/multiprocessing.py +1 -3
  488. ansible/utils/native_jinja.py +1 -3
  489. ansible/utils/path.py +1 -2
  490. ansible/utils/plugin_docs.py +7 -6
  491. ansible/utils/py3compat.py +17 -55
  492. ansible/utils/sentinel.py +1 -3
  493. ansible/utils/shlex.py +1 -3
  494. ansible/utils/singleton.py +1 -3
  495. ansible/utils/ssh_functions.py +1 -3
  496. ansible/utils/unicode.py +1 -3
  497. ansible/utils/unsafe_proxy.py +1 -2
  498. ansible/utils/vars.py +6 -8
  499. ansible/utils/version.py +1 -3
  500. ansible/vars/clean.py +1 -3
  501. ansible/vars/fact_cache.py +1 -2
  502. ansible/vars/hostvars.py +9 -29
  503. ansible/vars/manager.py +24 -6
  504. ansible/vars/reserved.py +1 -3
  505. {ansible_core-2.16.5.data → ansible_core-2.17.0b1.data}/scripts/ansible-test +1 -2
  506. {ansible_core-2.16.5.dist-info → ansible_core-2.17.0b1.dist-info}/METADATA +3 -3
  507. ansible_core-2.17.0b1.dist-info/RECORD +987 -0
  508. ansible_test/__init__.py +1 -2
  509. ansible_test/_data/completion/docker.txt +7 -9
  510. ansible_test/_data/completion/remote.txt +6 -7
  511. ansible_test/_data/requirements/ansible-test.txt +0 -2
  512. ansible_test/_data/requirements/constraints.txt +1 -6
  513. ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
  514. ansible_test/_data/requirements/sanity.changelog.txt +3 -3
  515. ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
  516. ansible_test/_data/requirements/sanity.mypy.txt +12 -12
  517. ansible_test/_data/requirements/sanity.pep8.txt +1 -1
  518. ansible_test/_data/requirements/sanity.pylint.txt +7 -7
  519. ansible_test/_data/requirements/sanity.runtime-metadata.txt +1 -1
  520. ansible_test/_data/requirements/sanity.validate-modules.txt +3 -3
  521. ansible_test/_data/requirements/sanity.yamllint.txt +2 -2
  522. ansible_test/_internal/bootstrap.py +2 -2
  523. ansible_test/_internal/classification/__init__.py +0 -5
  524. ansible_test/_internal/commands/integration/cloud/cs.py +1 -1
  525. ansible_test/_internal/commands/integration/cloud/nios.py +1 -1
  526. ansible_test/_internal/commands/sanity/__init__.py +1 -27
  527. ansible_test/_internal/commands/sanity/ansible_doc.py +1 -1
  528. ansible_test/_internal/commands/sanity/import.py +0 -18
  529. ansible_test/_internal/commands/sanity/mypy.py +7 -10
  530. ansible_test/_internal/commands/units/__init__.py +1 -1
  531. ansible_test/_internal/config.py +0 -1
  532. ansible_test/_internal/content_config.py +0 -5
  533. ansible_test/_internal/coverage_util.py +0 -1
  534. ansible_test/_internal/docker_util.py +1 -1
  535. ansible_test/_internal/host_profiles.py +5 -4
  536. ansible_test/_internal/python_requirements.py +1 -119
  537. ansible_test/_internal/ssh.py +1 -0
  538. ansible_test/_internal/util.py +1 -1
  539. ansible_test/_internal/util_common.py +1 -1
  540. ansible_test/_internal/venv.py +10 -108
  541. ansible_test/_util/__init__.py +1 -2
  542. ansible_test/_util/controller/sanity/mypy/ansible-core.ini +0 -6
  543. ansible_test/_util/controller/sanity/mypy/modules.ini +0 -6
  544. ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +0 -1
  545. ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +0 -1
  546. ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +0 -1
  547. ansible_test/_util/controller/sanity/pylint/config/collection.cfg +0 -1
  548. ansible_test/_util/controller/sanity/pylint/config/default.cfg +0 -1
  549. ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -2
  550. ansible_test/_util/controller/sanity/shellcheck/exclude.txt +0 -1
  551. ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +31 -59
  552. ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +0 -7
  553. ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +10 -2
  554. ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -1
  555. ansible_test/_util/controller/sanity/yamllint/yamllinter.py +16 -4
  556. ansible_test/_util/target/__init__.py +1 -2
  557. ansible_test/_util/target/cli/ansible_test_cli_stub.py +1 -2
  558. ansible_test/_util/target/common/constants.py +1 -4
  559. ansible_test/_util/target/injector/python.py +4 -19
  560. ansible_test/_util/target/pytest/plugins/ansible_forked.py +2 -9
  561. ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py +1 -5
  562. ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +1 -2
  563. ansible_test/_util/target/sanity/compile/compile.py +3 -12
  564. ansible_test/_util/target/sanity/import/importer.py +1 -12
  565. ansible_test/_util/target/setup/bootstrap.sh +49 -105
  566. ansible_test/_util/target/setup/probe_cgroups.py +1 -2
  567. ansible_test/_util/target/setup/quiet_pip.py +1 -16
  568. ansible_test/_util/target/setup/requirements.py +9 -2
  569. ansible_test/_util/target/tools/virtualenvcheck.py +1 -2
  570. ansible_test/_util/target/tools/yamlcheck.py +1 -2
  571. ansible/module_utils/common/_json_compat.py +0 -16
  572. ansible/module_utils/compat/_selectors2.py +0 -655
  573. ansible/modules/yum.py +0 -1821
  574. ansible/plugins/action/yum.py +0 -111
  575. ansible_core-2.16.5.dist-info/RECORD +0 -1009
  576. ansible_test/_util/controller/sanity/code-smell/future-import-boilerplate.json +0 -7
  577. ansible_test/_util/controller/sanity/code-smell/future-import-boilerplate.py +0 -46
  578. ansible_test/_util/controller/sanity/code-smell/metaclass-boilerplate.json +0 -7
  579. ansible_test/_util/controller/sanity/code-smell/metaclass-boilerplate.py +0 -44
  580. ansible_test/_util/controller/sanity/code-smell/no-basestring.json +0 -7
  581. ansible_test/_util/controller/sanity/code-smell/no-basestring.py +0 -21
  582. ansible_test/_util/controller/sanity/code-smell/no-dict-iteritems.json +0 -7
  583. ansible_test/_util/controller/sanity/code-smell/no-dict-iteritems.py +0 -21
  584. ansible_test/_util/controller/sanity/code-smell/no-dict-iterkeys.json +0 -7
  585. ansible_test/_util/controller/sanity/code-smell/no-dict-iterkeys.py +0 -21
  586. ansible_test/_util/controller/sanity/code-smell/no-dict-itervalues.json +0 -7
  587. ansible_test/_util/controller/sanity/code-smell/no-dict-itervalues.py +0 -21
  588. ansible_test/_util/controller/sanity/code-smell/no-main-display.json +0 -10
  589. ansible_test/_util/controller/sanity/code-smell/no-main-display.py +0 -21
  590. ansible_test/_util/controller/sanity/code-smell/no-unicode-literals.json +0 -7
  591. ansible_test/_util/controller/sanity/code-smell/no-unicode-literals.py +0 -21
  592. ansible_test/_util/controller/tools/sslcheck.py +0 -22
  593. ansible_test/_util/target/common/__init__.py +0 -2
  594. {ansible_core-2.16.5.dist-info → ansible_core-2.17.0b1.dist-info}/COPYING +0 -0
  595. {ansible_core-2.16.5.dist-info → ansible_core-2.17.0b1.dist-info}/WHEEL +0 -0
  596. {ansible_core-2.16.5.dist-info → ansible_core-2.17.0b1.dist-info}/entry_points.txt +0 -0
  597. {ansible_core-2.16.5.dist-info → ansible_core-2.17.0b1.dist-info}/top_level.txt +0 -0
@@ -30,6 +30,7 @@ Python 2.6 and removed in Python 3.8. Still, there are many cases in which
30
30
  access to OS distribution information is needed. See `Python issue 1322
31
31
  <https://bugs.python.org/issue1322>`_ for more information.
32
32
  """
33
+ from __future__ import annotations
33
34
 
34
35
  import argparse
35
36
  import json
@@ -40,40 +41,39 @@ import shlex
40
41
  import subprocess
41
42
  import sys
42
43
  import warnings
44
+ from typing import (
45
+ Any,
46
+ Callable,
47
+ Dict,
48
+ Iterable,
49
+ Optional,
50
+ Sequence,
51
+ TextIO,
52
+ Tuple,
53
+ Type,
54
+ )
43
55
 
44
- __version__ = "1.6.0"
45
-
46
- # Use `if False` to avoid an ImportError on Python 2. After dropping Python 2
47
- # support, can use typing.TYPE_CHECKING instead. See:
48
- # https://docs.python.org/3/library/typing.html#typing.TYPE_CHECKING
49
- if False: # pragma: nocover
50
- from typing import (
51
- Any,
52
- Callable,
53
- Dict,
54
- Iterable,
55
- Optional,
56
- Sequence,
57
- TextIO,
58
- Tuple,
59
- Type,
60
- TypedDict,
61
- Union,
62
- )
56
+ try:
57
+ from typing import TypedDict
58
+ except ImportError:
59
+ # Python 3.7
60
+ TypedDict = dict
63
61
 
64
- VersionDict = TypedDict(
65
- "VersionDict", {"major": str, "minor": str, "build_number": str}
66
- )
67
- InfoDict = TypedDict(
68
- "InfoDict",
69
- {
70
- "id": str,
71
- "version": str,
72
- "version_parts": VersionDict,
73
- "like": str,
74
- "codename": str,
75
- },
76
- )
62
+ __version__ = "1.8.0"
63
+
64
+
65
+ class VersionDict(TypedDict):
66
+ major: str
67
+ minor: str
68
+ build_number: str
69
+
70
+
71
+ class InfoDict(TypedDict):
72
+ id: str
73
+ version: str
74
+ version_parts: VersionDict
75
+ like: str
76
+ codename: str
77
77
 
78
78
 
79
79
  _UNIXCONFDIR = os.environ.get("UNIXCONFDIR", "/etc")
@@ -126,6 +126,26 @@ _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN = re.compile(
126
126
  # Pattern for base file name of distro release file
127
127
  _DISTRO_RELEASE_BASENAME_PATTERN = re.compile(r"(\w+)[-_](release|version)$")
128
128
 
129
+ # Base file names to be looked up for if _UNIXCONFDIR is not readable.
130
+ _DISTRO_RELEASE_BASENAMES = [
131
+ "SuSE-release",
132
+ "arch-release",
133
+ "base-release",
134
+ "centos-release",
135
+ "fedora-release",
136
+ "gentoo-release",
137
+ "mageia-release",
138
+ "mandrake-release",
139
+ "mandriva-release",
140
+ "mandrivalinux-release",
141
+ "manjaro-release",
142
+ "oracle-release",
143
+ "redhat-release",
144
+ "rocky-release",
145
+ "sl-release",
146
+ "slackware-version",
147
+ ]
148
+
129
149
  # Base file names to be ignored when searching for distro release file
130
150
  _DISTRO_RELEASE_IGNORE_BASENAMES = (
131
151
  "debian_version",
@@ -138,8 +158,7 @@ _DISTRO_RELEASE_IGNORE_BASENAMES = (
138
158
  )
139
159
 
140
160
 
141
- def linux_distribution(full_distribution_name=True):
142
- # type: (bool) -> Tuple[str, str, str]
161
+ def linux_distribution(full_distribution_name: bool = True) -> Tuple[str, str, str]:
143
162
  """
144
163
  .. deprecated:: 1.6.0
145
164
 
@@ -182,8 +201,7 @@ def linux_distribution(full_distribution_name=True):
182
201
  return _distro.linux_distribution(full_distribution_name)
183
202
 
184
203
 
185
- def id():
186
- # type: () -> str
204
+ def id() -> str:
187
205
  """
188
206
  Return the distro ID of the current distribution, as a
189
207
  machine-readable string.
@@ -227,6 +245,7 @@ def id():
227
245
  "freebsd" FreeBSD
228
246
  "midnightbsd" MidnightBSD
229
247
  "rocky" Rocky Linux
248
+ "aix" AIX
230
249
  "guix" Guix System
231
250
  ============== =========================================
232
251
 
@@ -265,8 +284,7 @@ def id():
265
284
  return _distro.id()
266
285
 
267
286
 
268
- def name(pretty=False):
269
- # type: (bool) -> str
287
+ def name(pretty: bool = False) -> str:
270
288
  """
271
289
  Return the name of the current OS distribution, as a human-readable
272
290
  string.
@@ -305,8 +323,7 @@ def name(pretty=False):
305
323
  return _distro.name(pretty)
306
324
 
307
325
 
308
- def version(pretty=False, best=False):
309
- # type: (bool, bool) -> str
326
+ def version(pretty: bool = False, best: bool = False) -> str:
310
327
  """
311
328
  Return the version of the current OS distribution, as a human-readable
312
329
  string.
@@ -354,8 +371,7 @@ def version(pretty=False, best=False):
354
371
  return _distro.version(pretty, best)
355
372
 
356
373
 
357
- def version_parts(best=False):
358
- # type: (bool) -> Tuple[str, str, str]
374
+ def version_parts(best: bool = False) -> Tuple[str, str, str]:
359
375
  """
360
376
  Return the version of the current OS distribution as a tuple
361
377
  ``(major, minor, build_number)`` with items as follows:
@@ -372,8 +388,7 @@ def version_parts(best=False):
372
388
  return _distro.version_parts(best)
373
389
 
374
390
 
375
- def major_version(best=False):
376
- # type: (bool) -> str
391
+ def major_version(best: bool = False) -> str:
377
392
  """
378
393
  Return the major version of the current OS distribution, as a string,
379
394
  if provided.
@@ -386,8 +401,7 @@ def major_version(best=False):
386
401
  return _distro.major_version(best)
387
402
 
388
403
 
389
- def minor_version(best=False):
390
- # type: (bool) -> str
404
+ def minor_version(best: bool = False) -> str:
391
405
  """
392
406
  Return the minor version of the current OS distribution, as a string,
393
407
  if provided.
@@ -400,8 +414,7 @@ def minor_version(best=False):
400
414
  return _distro.minor_version(best)
401
415
 
402
416
 
403
- def build_number(best=False):
404
- # type: (bool) -> str
417
+ def build_number(best: bool = False) -> str:
405
418
  """
406
419
  Return the build number of the current OS distribution, as a string,
407
420
  if provided.
@@ -414,8 +427,7 @@ def build_number(best=False):
414
427
  return _distro.build_number(best)
415
428
 
416
429
 
417
- def like():
418
- # type: () -> str
430
+ def like() -> str:
419
431
  """
420
432
  Return a space-separated list of distro IDs of distributions that are
421
433
  closely related to the current OS distribution in regards to packaging
@@ -432,8 +444,7 @@ def like():
432
444
  return _distro.like()
433
445
 
434
446
 
435
- def codename():
436
- # type: () -> str
447
+ def codename() -> str:
437
448
  """
438
449
  Return the codename for the release of the current OS distribution,
439
450
  as a string.
@@ -457,8 +468,7 @@ def codename():
457
468
  return _distro.codename()
458
469
 
459
470
 
460
- def info(pretty=False, best=False):
461
- # type: (bool, bool) -> InfoDict
471
+ def info(pretty: bool = False, best: bool = False) -> InfoDict:
462
472
  """
463
473
  Return certain machine-readable information items about the current OS
464
474
  distribution in a dictionary, as shown in the following example:
@@ -502,8 +512,7 @@ def info(pretty=False, best=False):
502
512
  return _distro.info(pretty, best)
503
513
 
504
514
 
505
- def os_release_info():
506
- # type: () -> Dict[str, str]
515
+ def os_release_info() -> Dict[str, str]:
507
516
  """
508
517
  Return a dictionary containing key-value pairs for the information items
509
518
  from the os-release file data source of the current OS distribution.
@@ -513,8 +522,7 @@ def os_release_info():
513
522
  return _distro.os_release_info()
514
523
 
515
524
 
516
- def lsb_release_info():
517
- # type: () -> Dict[str, str]
525
+ def lsb_release_info() -> Dict[str, str]:
518
526
  """
519
527
  Return a dictionary containing key-value pairs for the information items
520
528
  from the lsb_release command data source of the current OS distribution.
@@ -525,8 +533,7 @@ def lsb_release_info():
525
533
  return _distro.lsb_release_info()
526
534
 
527
535
 
528
- def distro_release_info():
529
- # type: () -> Dict[str, str]
536
+ def distro_release_info() -> Dict[str, str]:
530
537
  """
531
538
  Return a dictionary containing key-value pairs for the information items
532
539
  from the distro release file data source of the current OS distribution.
@@ -536,8 +543,7 @@ def distro_release_info():
536
543
  return _distro.distro_release_info()
537
544
 
538
545
 
539
- def uname_info():
540
- # type: () -> Dict[str, str]
546
+ def uname_info() -> Dict[str, str]:
541
547
  """
542
548
  Return a dictionary containing key-value pairs for the information items
543
549
  from the distro release file data source of the current OS distribution.
@@ -545,8 +551,7 @@ def uname_info():
545
551
  return _distro.uname_info()
546
552
 
547
553
 
548
- def os_release_attr(attribute):
549
- # type: (str) -> str
554
+ def os_release_attr(attribute: str) -> str:
550
555
  """
551
556
  Return a single named information item from the os-release file data source
552
557
  of the current OS distribution.
@@ -565,8 +570,7 @@ def os_release_attr(attribute):
565
570
  return _distro.os_release_attr(attribute)
566
571
 
567
572
 
568
- def lsb_release_attr(attribute):
569
- # type: (str) -> str
573
+ def lsb_release_attr(attribute: str) -> str:
570
574
  """
571
575
  Return a single named information item from the lsb_release command output
572
576
  data source of the current OS distribution.
@@ -586,8 +590,7 @@ def lsb_release_attr(attribute):
586
590
  return _distro.lsb_release_attr(attribute)
587
591
 
588
592
 
589
- def distro_release_attr(attribute):
590
- # type: (str) -> str
593
+ def distro_release_attr(attribute: str) -> str:
591
594
  """
592
595
  Return a single named information item from the distro release file
593
596
  data source of the current OS distribution.
@@ -606,8 +609,7 @@ def distro_release_attr(attribute):
606
609
  return _distro.distro_release_attr(attribute)
607
610
 
608
611
 
609
- def uname_attr(attribute):
610
- # type: (str) -> str
612
+ def uname_attr(attribute: str) -> str:
611
613
  """
612
614
  Return a single named information item from the distro release file
613
615
  data source of the current OS distribution.
@@ -628,25 +630,23 @@ try:
628
630
  from functools import cached_property
629
631
  except ImportError:
630
632
  # Python < 3.8
631
- class cached_property(object): # type: ignore
633
+ class cached_property: # type: ignore
632
634
  """A version of @property which caches the value. On access, it calls the
633
635
  underlying function and sets the value in `__dict__` so future accesses
634
636
  will not re-call the property.
635
637
  """
636
638
 
637
- def __init__(self, f):
638
- # type: (Callable[[Any], Any]) -> None
639
+ def __init__(self, f: Callable[[Any], Any]) -> None:
639
640
  self._fname = f.__name__
640
641
  self._f = f
641
642
 
642
- def __get__(self, obj, owner):
643
- # type: (Any, Type[Any]) -> Any
644
- assert obj is not None, "call {} on an instance".format(self._fname)
643
+ def __get__(self, obj: Any, owner: Type[Any]) -> Any:
644
+ assert obj is not None, f"call {self._fname} on an instance"
645
645
  ret = obj.__dict__[self._fname] = self._f(obj)
646
646
  return ret
647
647
 
648
648
 
649
- class LinuxDistribution(object):
649
+ class LinuxDistribution:
650
650
  """
651
651
  Provides information about a OS distribution.
652
652
 
@@ -666,13 +666,13 @@ class LinuxDistribution(object):
666
666
 
667
667
  def __init__(
668
668
  self,
669
- include_lsb=True,
670
- os_release_file="",
671
- distro_release_file="",
672
- include_uname=True,
673
- root_dir=None,
674
- ):
675
- # type: (bool, str, str, bool, Optional[str]) -> None
669
+ include_lsb: Optional[bool] = None,
670
+ os_release_file: str = "",
671
+ distro_release_file: str = "",
672
+ include_uname: Optional[bool] = None,
673
+ root_dir: Optional[str] = None,
674
+ include_oslevel: Optional[bool] = None,
675
+ ) -> None:
676
676
  """
677
677
  The initialization method of this class gathers information from the
678
678
  available data sources, and stores that in private instance attributes.
@@ -712,7 +712,13 @@ class LinuxDistribution(object):
712
712
  be empty.
713
713
 
714
714
  * ``root_dir`` (string): The absolute path to the root directory to use
715
- to find distro-related information files.
715
+ to find distro-related information files. Note that ``include_*``
716
+ parameters must not be enabled in combination with ``root_dir``.
717
+
718
+ * ``include_oslevel`` (bool): Controls whether (AIX) oslevel command
719
+ output is included as a data source. If the oslevel command is not
720
+ available in the program execution path the data source will be
721
+ empty.
716
722
 
717
723
  Public instance attributes:
718
724
 
@@ -731,9 +737,20 @@ class LinuxDistribution(object):
731
737
  parameter. This controls whether the uname information will
732
738
  be loaded.
733
739
 
740
+ * ``include_oslevel`` (bool): The result of the ``include_oslevel``
741
+ parameter. This controls whether (AIX) oslevel information will be
742
+ loaded.
743
+
744
+ * ``root_dir`` (string): The result of the ``root_dir`` parameter.
745
+ The absolute path to the root directory to use to find distro-related
746
+ information files.
747
+
734
748
  Raises:
735
749
 
736
- * :py:exc:`IOError`: Some I/O issue with an os-release file or distro
750
+ * :py:exc:`ValueError`: Initialization parameters combination is not
751
+ supported.
752
+
753
+ * :py:exc:`OSError`: Some I/O issue with an os-release file or distro
737
754
  release file.
738
755
 
739
756
  * :py:exc:`UnicodeError`: A data source has unexpected characters or
@@ -763,11 +780,24 @@ class LinuxDistribution(object):
763
780
  self.os_release_file = usr_lib_os_release_file
764
781
 
765
782
  self.distro_release_file = distro_release_file or "" # updated later
766
- self.include_lsb = include_lsb
767
- self.include_uname = include_uname
768
783
 
769
- def __repr__(self):
770
- # type: () -> str
784
+ is_root_dir_defined = root_dir is not None
785
+ if is_root_dir_defined and (include_lsb or include_uname or include_oslevel):
786
+ raise ValueError(
787
+ "Including subprocess data sources from specific root_dir is disallowed"
788
+ " to prevent false information"
789
+ )
790
+ self.include_lsb = (
791
+ include_lsb if include_lsb is not None else not is_root_dir_defined
792
+ )
793
+ self.include_uname = (
794
+ include_uname if include_uname is not None else not is_root_dir_defined
795
+ )
796
+ self.include_oslevel = (
797
+ include_oslevel if include_oslevel is not None else not is_root_dir_defined
798
+ )
799
+
800
+ def __repr__(self) -> str:
771
801
  """Return repr of all info"""
772
802
  return (
773
803
  "LinuxDistribution("
@@ -775,14 +805,18 @@ class LinuxDistribution(object):
775
805
  "distro_release_file={self.distro_release_file!r}, "
776
806
  "include_lsb={self.include_lsb!r}, "
777
807
  "include_uname={self.include_uname!r}, "
808
+ "include_oslevel={self.include_oslevel!r}, "
809
+ "root_dir={self.root_dir!r}, "
778
810
  "_os_release_info={self._os_release_info!r}, "
779
811
  "_lsb_release_info={self._lsb_release_info!r}, "
780
812
  "_distro_release_info={self._distro_release_info!r}, "
781
- "_uname_info={self._uname_info!r})".format(self=self)
813
+ "_uname_info={self._uname_info!r}, "
814
+ "_oslevel_info={self._oslevel_info!r})".format(self=self)
782
815
  )
783
816
 
784
- def linux_distribution(self, full_distribution_name=True):
785
- # type: (bool) -> Tuple[str, str, str]
817
+ def linux_distribution(
818
+ self, full_distribution_name: bool = True
819
+ ) -> Tuple[str, str, str]:
786
820
  """
787
821
  Return information about the OS distribution that is compatible
788
822
  with Python's :func:`platform.linux_distribution`, supporting a subset
@@ -796,15 +830,13 @@ class LinuxDistribution(object):
796
830
  self._os_release_info.get("release_codename") or self.codename(),
797
831
  )
798
832
 
799
- def id(self):
800
- # type: () -> str
833
+ def id(self) -> str:
801
834
  """Return the distro ID of the OS distribution, as a string.
802
835
 
803
836
  For details, see :func:`distro.id`.
804
837
  """
805
838
 
806
- def normalize(distro_id, table):
807
- # type: (str, Dict[str, str]) -> str
839
+ def normalize(distro_id: str, table: Dict[str, str]) -> str:
808
840
  distro_id = distro_id.lower().replace(" ", "_")
809
841
  return table.get(distro_id, distro_id)
810
842
 
@@ -826,8 +858,7 @@ class LinuxDistribution(object):
826
858
 
827
859
  return ""
828
860
 
829
- def name(self, pretty=False):
830
- # type: (bool) -> str
861
+ def name(self, pretty: bool = False) -> str:
831
862
  """
832
863
  Return the name of the OS distribution, as a string.
833
864
 
@@ -847,11 +878,10 @@ class LinuxDistribution(object):
847
878
  name = self.distro_release_attr("name") or self.uname_attr("name")
848
879
  version = self.version(pretty=True)
849
880
  if version:
850
- name = name + " " + version
881
+ name = f"{name} {version}"
851
882
  return name or ""
852
883
 
853
- def version(self, pretty=False, best=False):
854
- # type: (bool, bool) -> str
884
+ def version(self, pretty: bool = False, best: bool = False) -> str:
855
885
  """
856
886
  Return the version of the OS distribution, as a string.
857
887
 
@@ -869,7 +899,10 @@ class LinuxDistribution(object):
869
899
  ).get("version_id", ""),
870
900
  self.uname_attr("release"),
871
901
  ]
872
- if self.id() == "debian" or "debian" in self.like().split():
902
+ if self.uname_attr("id").startswith("aix"):
903
+ # On AIX platforms, prefer oslevel command output.
904
+ versions.insert(0, self.oslevel_info())
905
+ elif self.id() == "debian" or "debian" in self.like().split():
873
906
  # On Debian-like, add debian_version file content to candidates list.
874
907
  versions.append(self._debian_version)
875
908
  version = ""
@@ -887,11 +920,10 @@ class LinuxDistribution(object):
887
920
  version = v
888
921
  break
889
922
  if pretty and version and self.codename():
890
- version = "{0} ({1})".format(version, self.codename())
923
+ version = f"{version} ({self.codename()})"
891
924
  return version
892
925
 
893
- def version_parts(self, best=False):
894
- # type: (bool) -> Tuple[str, str, str]
926
+ def version_parts(self, best: bool = False) -> Tuple[str, str, str]:
895
927
  """
896
928
  Return the version of the OS distribution, as a tuple of version
897
929
  numbers.
@@ -907,8 +939,7 @@ class LinuxDistribution(object):
907
939
  return major, minor or "", build_number or ""
908
940
  return "", "", ""
909
941
 
910
- def major_version(self, best=False):
911
- # type: (bool) -> str
942
+ def major_version(self, best: bool = False) -> str:
912
943
  """
913
944
  Return the major version number of the current distribution.
914
945
 
@@ -916,8 +947,7 @@ class LinuxDistribution(object):
916
947
  """
917
948
  return self.version_parts(best)[0]
918
949
 
919
- def minor_version(self, best=False):
920
- # type: (bool) -> str
950
+ def minor_version(self, best: bool = False) -> str:
921
951
  """
922
952
  Return the minor version number of the current distribution.
923
953
 
@@ -925,8 +955,7 @@ class LinuxDistribution(object):
925
955
  """
926
956
  return self.version_parts(best)[1]
927
957
 
928
- def build_number(self, best=False):
929
- # type: (bool) -> str
958
+ def build_number(self, best: bool = False) -> str:
930
959
  """
931
960
  Return the build number of the current distribution.
932
961
 
@@ -934,8 +963,7 @@ class LinuxDistribution(object):
934
963
  """
935
964
  return self.version_parts(best)[2]
936
965
 
937
- def like(self):
938
- # type: () -> str
966
+ def like(self) -> str:
939
967
  """
940
968
  Return the IDs of distributions that are like the OS distribution.
941
969
 
@@ -943,8 +971,7 @@ class LinuxDistribution(object):
943
971
  """
944
972
  return self.os_release_attr("id_like") or ""
945
973
 
946
- def codename(self):
947
- # type: () -> str
974
+ def codename(self) -> str:
948
975
  """
949
976
  Return the codename of the OS distribution.
950
977
 
@@ -961,8 +988,7 @@ class LinuxDistribution(object):
961
988
  or ""
962
989
  )
963
990
 
964
- def info(self, pretty=False, best=False):
965
- # type: (bool, bool) -> InfoDict
991
+ def info(self, pretty: bool = False, best: bool = False) -> InfoDict:
966
992
  """
967
993
  Return certain machine-readable information about the OS
968
994
  distribution.
@@ -981,8 +1007,7 @@ class LinuxDistribution(object):
981
1007
  codename=self.codename(),
982
1008
  )
983
1009
 
984
- def os_release_info(self):
985
- # type: () -> Dict[str, str]
1010
+ def os_release_info(self) -> Dict[str, str]:
986
1011
  """
987
1012
  Return a dictionary containing key-value pairs for the information
988
1013
  items from the os-release file data source of the OS distribution.
@@ -991,8 +1016,7 @@ class LinuxDistribution(object):
991
1016
  """
992
1017
  return self._os_release_info
993
1018
 
994
- def lsb_release_info(self):
995
- # type: () -> Dict[str, str]
1019
+ def lsb_release_info(self) -> Dict[str, str]:
996
1020
  """
997
1021
  Return a dictionary containing key-value pairs for the information
998
1022
  items from the lsb_release command data source of the OS
@@ -1002,8 +1026,7 @@ class LinuxDistribution(object):
1002
1026
  """
1003
1027
  return self._lsb_release_info
1004
1028
 
1005
- def distro_release_info(self):
1006
- # type: () -> Dict[str, str]
1029
+ def distro_release_info(self) -> Dict[str, str]:
1007
1030
  """
1008
1031
  Return a dictionary containing key-value pairs for the information
1009
1032
  items from the distro release file data source of the OS
@@ -1013,8 +1036,7 @@ class LinuxDistribution(object):
1013
1036
  """
1014
1037
  return self._distro_release_info
1015
1038
 
1016
- def uname_info(self):
1017
- # type: () -> Dict[str, str]
1039
+ def uname_info(self) -> Dict[str, str]:
1018
1040
  """
1019
1041
  Return a dictionary containing key-value pairs for the information
1020
1042
  items from the uname command data source of the OS distribution.
@@ -1023,8 +1045,13 @@ class LinuxDistribution(object):
1023
1045
  """
1024
1046
  return self._uname_info
1025
1047
 
1026
- def os_release_attr(self, attribute):
1027
- # type: (str) -> str
1048
+ def oslevel_info(self) -> str:
1049
+ """
1050
+ Return AIX' oslevel command output.
1051
+ """
1052
+ return self._oslevel_info
1053
+
1054
+ def os_release_attr(self, attribute: str) -> str:
1028
1055
  """
1029
1056
  Return a single named information item from the os-release file data
1030
1057
  source of the OS distribution.
@@ -1033,8 +1060,7 @@ class LinuxDistribution(object):
1033
1060
  """
1034
1061
  return self._os_release_info.get(attribute, "")
1035
1062
 
1036
- def lsb_release_attr(self, attribute):
1037
- # type: (str) -> str
1063
+ def lsb_release_attr(self, attribute: str) -> str:
1038
1064
  """
1039
1065
  Return a single named information item from the lsb_release command
1040
1066
  output data source of the OS distribution.
@@ -1043,8 +1069,7 @@ class LinuxDistribution(object):
1043
1069
  """
1044
1070
  return self._lsb_release_info.get(attribute, "")
1045
1071
 
1046
- def distro_release_attr(self, attribute):
1047
- # type: (str) -> str
1072
+ def distro_release_attr(self, attribute: str) -> str:
1048
1073
  """
1049
1074
  Return a single named information item from the distro release file
1050
1075
  data source of the OS distribution.
@@ -1053,8 +1078,7 @@ class LinuxDistribution(object):
1053
1078
  """
1054
1079
  return self._distro_release_info.get(attribute, "")
1055
1080
 
1056
- def uname_attr(self, attribute):
1057
- # type: (str) -> str
1081
+ def uname_attr(self, attribute: str) -> str:
1058
1082
  """
1059
1083
  Return a single named information item from the uname command
1060
1084
  output data source of the OS distribution.
@@ -1064,8 +1088,7 @@ class LinuxDistribution(object):
1064
1088
  return self._uname_info.get(attribute, "")
1065
1089
 
1066
1090
  @cached_property
1067
- def _os_release_info(self):
1068
- # type: () -> Dict[str, str]
1091
+ def _os_release_info(self) -> Dict[str, str]:
1069
1092
  """
1070
1093
  Get the information items from the specified os-release file.
1071
1094
 
@@ -1073,13 +1096,12 @@ class LinuxDistribution(object):
1073
1096
  A dictionary containing all information items.
1074
1097
  """
1075
1098
  if os.path.isfile(self.os_release_file):
1076
- with open(self.os_release_file) as release_file:
1099
+ with open(self.os_release_file, encoding="utf-8") as release_file:
1077
1100
  return self._parse_os_release_content(release_file)
1078
1101
  return {}
1079
1102
 
1080
1103
  @staticmethod
1081
- def _parse_os_release_content(lines):
1082
- # type: (TextIO) -> Dict[str, str]
1104
+ def _parse_os_release_content(lines: TextIO) -> Dict[str, str]:
1083
1105
  """
1084
1106
  Parse the lines of an os-release file.
1085
1107
 
@@ -1096,16 +1118,6 @@ class LinuxDistribution(object):
1096
1118
  lexer = shlex.shlex(lines, posix=True)
1097
1119
  lexer.whitespace_split = True
1098
1120
 
1099
- # The shlex module defines its `wordchars` variable using literals,
1100
- # making it dependent on the encoding of the Python source file.
1101
- # In Python 2.6 and 2.7, the shlex source file is encoded in
1102
- # 'iso-8859-1', and the `wordchars` variable is defined as a byte
1103
- # string. This causes a UnicodeDecodeError to be raised when the
1104
- # parsed content is a unicode object. The following fix resolves that
1105
- # (... but it should be fixed in shlex...):
1106
- if sys.version_info[0] == 2 and isinstance(lexer.wordchars, bytes):
1107
- lexer.wordchars = lexer.wordchars.decode("iso-8859-1")
1108
-
1109
1121
  tokens = list(lexer)
1110
1122
  for token in tokens:
1111
1123
  # At this point, all shell-like parsing has been done (i.e.
@@ -1139,8 +1151,7 @@ class LinuxDistribution(object):
1139
1151
  return props
1140
1152
 
1141
1153
  @cached_property
1142
- def _lsb_release_info(self):
1143
- # type: () -> Dict[str, str]
1154
+ def _lsb_release_info(self) -> Dict[str, str]:
1144
1155
  """
1145
1156
  Get the information items from the lsb_release command output.
1146
1157
 
@@ -1149,19 +1160,17 @@ class LinuxDistribution(object):
1149
1160
  """
1150
1161
  if not self.include_lsb:
1151
1162
  return {}
1152
- with open(os.devnull, "wb") as devnull:
1153
- try:
1154
- cmd = ("lsb_release", "-a")
1155
- stdout = subprocess.check_output(cmd, stderr=devnull)
1156
- # Command not found or lsb_release returned error
1157
- except (OSError, subprocess.CalledProcessError):
1158
- return {}
1163
+ try:
1164
+ cmd = ("lsb_release", "-a")
1165
+ stdout = subprocess.check_output(cmd, stderr=subprocess.DEVNULL)
1166
+ # Command not found or lsb_release returned error
1167
+ except (OSError, subprocess.CalledProcessError):
1168
+ return {}
1159
1169
  content = self._to_str(stdout).splitlines()
1160
1170
  return self._parse_lsb_release_content(content)
1161
1171
 
1162
1172
  @staticmethod
1163
- def _parse_lsb_release_content(lines):
1164
- # type: (Iterable[str]) -> Dict[str, str]
1173
+ def _parse_lsb_release_content(lines: Iterable[str]) -> Dict[str, str]:
1165
1174
  """
1166
1175
  Parse the output of the lsb_release command.
1167
1176
 
@@ -1185,31 +1194,39 @@ class LinuxDistribution(object):
1185
1194
  return props
1186
1195
 
1187
1196
  @cached_property
1188
- def _uname_info(self):
1189
- # type: () -> Dict[str, str]
1197
+ def _uname_info(self) -> Dict[str, str]:
1190
1198
  if not self.include_uname:
1191
1199
  return {}
1192
- with open(os.devnull, "wb") as devnull:
1193
- try:
1194
- cmd = ("uname", "-rs")
1195
- stdout = subprocess.check_output(cmd, stderr=devnull)
1196
- except OSError:
1197
- return {}
1200
+ try:
1201
+ cmd = ("uname", "-rs")
1202
+ stdout = subprocess.check_output(cmd, stderr=subprocess.DEVNULL)
1203
+ except OSError:
1204
+ return {}
1198
1205
  content = self._to_str(stdout).splitlines()
1199
1206
  return self._parse_uname_content(content)
1200
1207
 
1201
1208
  @cached_property
1202
- def _debian_version(self):
1203
- # type: () -> str
1209
+ def _oslevel_info(self) -> str:
1210
+ if not self.include_oslevel:
1211
+ return ""
1212
+ try:
1213
+ stdout = subprocess.check_output("oslevel", stderr=subprocess.DEVNULL)
1214
+ except (OSError, subprocess.CalledProcessError):
1215
+ return ""
1216
+ return self._to_str(stdout).strip()
1217
+
1218
+ @cached_property
1219
+ def _debian_version(self) -> str:
1204
1220
  try:
1205
- with open(os.path.join(self.etc_dir, "debian_version")) as fp:
1221
+ with open(
1222
+ os.path.join(self.etc_dir, "debian_version"), encoding="ascii"
1223
+ ) as fp:
1206
1224
  return fp.readline().rstrip()
1207
- except (OSError, IOError):
1225
+ except FileNotFoundError:
1208
1226
  return ""
1209
1227
 
1210
1228
  @staticmethod
1211
- def _parse_uname_content(lines):
1212
- # type: (Sequence[str]) -> Dict[str, str]
1229
+ def _parse_uname_content(lines: Sequence[str]) -> Dict[str, str]:
1213
1230
  if not lines:
1214
1231
  return {}
1215
1232
  props = {}
@@ -1228,23 +1245,12 @@ class LinuxDistribution(object):
1228
1245
  return props
1229
1246
 
1230
1247
  @staticmethod
1231
- def _to_str(text):
1232
- # type: (Union[bytes, str]) -> str
1248
+ def _to_str(bytestring: bytes) -> str:
1233
1249
  encoding = sys.getfilesystemencoding()
1234
- encoding = "utf-8" if encoding == "ascii" else encoding
1235
-
1236
- if sys.version_info[0] >= 3:
1237
- if isinstance(text, bytes):
1238
- return text.decode(encoding)
1239
- else:
1240
- if isinstance(text, unicode): # noqa
1241
- return text.encode(encoding)
1242
-
1243
- return text
1250
+ return bytestring.decode(encoding)
1244
1251
 
1245
1252
  @cached_property
1246
- def _distro_release_info(self):
1247
- # type: () -> Dict[str, str]
1253
+ def _distro_release_info(self) -> Dict[str, str]:
1248
1254
  """
1249
1255
  Get the information items from the specified distro release file.
1250
1256
 
@@ -1261,14 +1267,14 @@ class LinuxDistribution(object):
1261
1267
  # file), because we want to use what was specified as best as
1262
1268
  # possible.
1263
1269
  match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename)
1264
- if "name" in distro_info and "cloudlinux" in distro_info["name"].lower():
1265
- distro_info["id"] = "cloudlinux"
1266
- elif match:
1267
- distro_info["id"] = match.group(1)
1268
- return distro_info
1269
1270
  else:
1270
1271
  try:
1271
- basenames = os.listdir(self.etc_dir)
1272
+ basenames = [
1273
+ basename
1274
+ for basename in os.listdir(self.etc_dir)
1275
+ if basename not in _DISTRO_RELEASE_IGNORE_BASENAMES
1276
+ and os.path.isfile(os.path.join(self.etc_dir, basename))
1277
+ ]
1272
1278
  # We sort for repeatability in cases where there are multiple
1273
1279
  # distro specific files; e.g. CentOS, Oracle, Enterprise all
1274
1280
  # containing `redhat-release` on top of their own.
@@ -1278,42 +1284,31 @@ class LinuxDistribution(object):
1278
1284
  # sure about the *-release files. Check common entries of
1279
1285
  # /etc for information. If they turn out to not be there the
1280
1286
  # error is handled in `_parse_distro_release_file()`.
1281
- basenames = [
1282
- "SuSE-release",
1283
- "arch-release",
1284
- "base-release",
1285
- "centos-release",
1286
- "fedora-release",
1287
- "gentoo-release",
1288
- "mageia-release",
1289
- "mandrake-release",
1290
- "mandriva-release",
1291
- "mandrivalinux-release",
1292
- "manjaro-release",
1293
- "oracle-release",
1294
- "redhat-release",
1295
- "rocky-release",
1296
- "sl-release",
1297
- "slackware-version",
1298
- ]
1287
+ basenames = _DISTRO_RELEASE_BASENAMES
1299
1288
  for basename in basenames:
1300
- if basename in _DISTRO_RELEASE_IGNORE_BASENAMES:
1301
- continue
1302
1289
  match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename)
1303
- if match:
1304
- filepath = os.path.join(self.etc_dir, basename)
1305
- distro_info = self._parse_distro_release_file(filepath)
1306
- if "name" in distro_info:
1307
- # The name is always present if the pattern matches
1308
- self.distro_release_file = filepath
1309
- distro_info["id"] = match.group(1)
1310
- if "cloudlinux" in distro_info["name"].lower():
1311
- distro_info["id"] = "cloudlinux"
1312
- return distro_info
1313
- return {}
1290
+ if match is None:
1291
+ continue
1292
+ filepath = os.path.join(self.etc_dir, basename)
1293
+ distro_info = self._parse_distro_release_file(filepath)
1294
+ # The name is always present if the pattern matches.
1295
+ if "name" not in distro_info:
1296
+ continue
1297
+ self.distro_release_file = filepath
1298
+ break
1299
+ else: # the loop didn't "break": no candidate.
1300
+ return {}
1301
+
1302
+ if match is not None:
1303
+ distro_info["id"] = match.group(1)
1304
+
1305
+ # CloudLinux < 7: manually enrich info with proper id.
1306
+ if "cloudlinux" in distro_info.get("name", "").lower():
1307
+ distro_info["id"] = "cloudlinux"
1308
+
1309
+ return distro_info
1314
1310
 
1315
- def _parse_distro_release_file(self, filepath):
1316
- # type: (str) -> Dict[str, str]
1311
+ def _parse_distro_release_file(self, filepath: str) -> Dict[str, str]:
1317
1312
  """
1318
1313
  Parse a distro release file.
1319
1314
 
@@ -1325,19 +1320,18 @@ class LinuxDistribution(object):
1325
1320
  A dictionary containing all information items.
1326
1321
  """
1327
1322
  try:
1328
- with open(filepath) as fp:
1323
+ with open(filepath, encoding="utf-8") as fp:
1329
1324
  # Only parse the first line. For instance, on SLES there
1330
1325
  # are multiple lines. We don't want them...
1331
1326
  return self._parse_distro_release_content(fp.readline())
1332
- except (OSError, IOError):
1327
+ except OSError:
1333
1328
  # Ignore not being able to read a specific, seemingly version
1334
1329
  # related file.
1335
1330
  # See https://github.com/python-distro/distro/issues/162
1336
1331
  return {}
1337
1332
 
1338
1333
  @staticmethod
1339
- def _parse_distro_release_content(line):
1340
- # type: (str) -> Dict[str, str]
1334
+ def _parse_distro_release_content(line: str) -> Dict[str, str]:
1341
1335
  """
1342
1336
  Parse a line from a distro release file.
1343
1337
 
@@ -1365,8 +1359,7 @@ class LinuxDistribution(object):
1365
1359
  _distro = LinuxDistribution()
1366
1360
 
1367
1361
 
1368
- def main():
1369
- # type: () -> None
1362
+ def main() -> None:
1370
1363
  logger = logging.getLogger(__name__)
1371
1364
  logger.setLevel(logging.DEBUG)
1372
1365
  logger.addHandler(logging.StreamHandler(sys.stdout))
@@ -1388,7 +1381,10 @@ def main():
1388
1381
 
1389
1382
  if args.root_dir:
1390
1383
  dist = LinuxDistribution(
1391
- include_lsb=False, include_uname=False, root_dir=args.root_dir
1384
+ include_lsb=False,
1385
+ include_uname=False,
1386
+ include_oslevel=False,
1387
+ root_dir=args.root_dir,
1392
1388
  )
1393
1389
  else:
1394
1390
  dist = _distro