ansible-core 2.17.6rc1__py3-none-any.whl → 2.18.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 (325) hide show
  1. ansible/__main__.py +2 -17
  2. ansible/cli/__init__.py +3 -15
  3. ansible/cli/config.py +187 -24
  4. ansible/cli/console.py +1 -1
  5. ansible/cli/doc.py +38 -16
  6. ansible/cli/galaxy.py +3 -49
  7. ansible/cli/inventory.py +2 -2
  8. ansible/cli/pull.py +2 -2
  9. ansible/cli/scripts/ansible_connection_cli_stub.py +1 -10
  10. ansible/config/base.yml +127 -57
  11. ansible/config/manager.py +89 -11
  12. ansible/constants.py +32 -9
  13. ansible/errors/__init__.py +5 -0
  14. ansible/executor/interpreter_discovery.py +1 -1
  15. ansible/executor/play_iterator.py +16 -0
  16. ansible/executor/playbook_executor.py +1 -4
  17. ansible/executor/powershell/become_wrapper.ps1 +4 -5
  18. ansible/executor/powershell/bootstrap_wrapper.ps1 +2 -3
  19. ansible/executor/powershell/exec_wrapper.ps1 +1 -1
  20. ansible/executor/powershell/module_manifest.py +2 -2
  21. ansible/executor/task_executor.py +50 -39
  22. ansible/executor/task_queue_manager.py +1 -1
  23. ansible/executor/task_result.py +1 -1
  24. ansible/galaxy/api.py +3 -4
  25. ansible/galaxy/collection/__init__.py +21 -10
  26. ansible/galaxy/collection/concrete_artifact_manager.py +2 -2
  27. ansible/galaxy/collection/galaxy_api_proxy.py +10 -16
  28. ansible/galaxy/collection/gpg.py +17 -23
  29. ansible/galaxy/data/COPYING +7 -0
  30. ansible/galaxy/data/apb/Dockerfile.j2 +1 -0
  31. ansible/galaxy/data/apb/Makefile.j2 +1 -0
  32. ansible/galaxy/data/apb/README.md +7 -3
  33. ansible/galaxy/data/apb/apb.yml.j2 +1 -0
  34. ansible/galaxy/data/apb/defaults/main.yml.j2 +1 -0
  35. ansible/galaxy/data/apb/handlers/main.yml.j2 +1 -0
  36. ansible/galaxy/data/apb/meta/main.yml.j2 +1 -0
  37. ansible/galaxy/data/apb/playbooks/deprovision.yml.j2 +1 -0
  38. ansible/galaxy/data/apb/playbooks/provision.yml.j2 +1 -0
  39. ansible/galaxy/data/apb/tasks/main.yml.j2 +1 -0
  40. ansible/galaxy/data/apb/tests/ansible.cfg +1 -0
  41. ansible/galaxy/data/apb/tests/inventory +1 -0
  42. ansible/galaxy/data/apb/tests/test.yml.j2 +1 -0
  43. ansible/galaxy/data/apb/vars/main.yml.j2 +1 -0
  44. ansible/galaxy/data/collections_galaxy_meta.yml +1 -0
  45. ansible/galaxy/data/container/defaults/main.yml.j2 +1 -0
  46. ansible/galaxy/data/container/handlers/main.yml.j2 +1 -0
  47. ansible/galaxy/data/container/meta/container.yml.j2 +1 -0
  48. ansible/galaxy/data/container/meta/main.yml.j2 +1 -0
  49. ansible/galaxy/data/container/tasks/main.yml.j2 +1 -0
  50. ansible/galaxy/data/container/tests/ansible.cfg +1 -0
  51. ansible/galaxy/data/container/tests/inventory +1 -0
  52. ansible/galaxy/data/container/tests/test.yml.j2 +1 -0
  53. ansible/galaxy/data/container/vars/main.yml.j2 +1 -0
  54. ansible/galaxy/data/default/collection/README.md.j2 +1 -0
  55. ansible/galaxy/data/default/collection/galaxy.yml.j2 +1 -0
  56. ansible/galaxy/data/default/collection/meta/runtime.yml +1 -0
  57. ansible/galaxy/data/default/collection/plugins/README.md.j2 +1 -0
  58. ansible/galaxy/data/default/role/defaults/main.yml.j2 +1 -0
  59. ansible/galaxy/data/default/role/handlers/main.yml.j2 +1 -0
  60. ansible/galaxy/data/default/role/meta/main.yml.j2 +1 -0
  61. ansible/galaxy/data/default/role/tasks/main.yml.j2 +1 -0
  62. ansible/galaxy/data/default/role/tests/inventory +1 -0
  63. ansible/galaxy/data/default/role/tests/test.yml.j2 +1 -0
  64. ansible/galaxy/data/default/role/vars/main.yml.j2 +1 -0
  65. ansible/galaxy/data/network/cliconf_plugins/example.py.j2 +1 -0
  66. ansible/galaxy/data/network/defaults/main.yml.j2 +1 -0
  67. ansible/galaxy/data/network/library/example_command.py.j2 +1 -0
  68. ansible/galaxy/data/network/library/example_config.py.j2 +1 -0
  69. ansible/galaxy/data/network/library/example_facts.py.j2 +1 -0
  70. ansible/galaxy/data/network/meta/main.yml.j2 +1 -0
  71. ansible/galaxy/data/network/module_utils/example.py.j2 +1 -0
  72. ansible/galaxy/data/network/netconf_plugins/example.py.j2 +1 -0
  73. ansible/galaxy/data/network/tasks/main.yml.j2 +1 -0
  74. ansible/galaxy/data/network/terminal_plugins/example.py.j2 +1 -0
  75. ansible/galaxy/data/network/tests/inventory +1 -0
  76. ansible/galaxy/data/network/tests/test.yml.j2 +1 -0
  77. ansible/galaxy/data/network/vars/main.yml.j2 +1 -0
  78. ansible/galaxy/dependency_resolution/providers.py +3 -3
  79. ansible/galaxy/role.py +1 -1
  80. ansible/galaxy/token.py +20 -8
  81. ansible/keyword_desc.yml +1 -1
  82. ansible/module_utils/_internal/__init__.py +0 -0
  83. ansible/module_utils/_internal/_concurrent/__init__.py +0 -0
  84. ansible/module_utils/_internal/_concurrent/_daemon_threading.py +28 -0
  85. ansible/module_utils/_internal/_concurrent/_futures.py +21 -0
  86. ansible/module_utils/ansible_release.py +2 -2
  87. ansible/module_utils/api.py +2 -2
  88. ansible/module_utils/basic.py +8 -8
  89. ansible/module_utils/common/collections.py +1 -1
  90. ansible/module_utils/common/file.py +0 -6
  91. ansible/module_utils/common/process.py +22 -9
  92. ansible/module_utils/common/text/converters.py +5 -8
  93. ansible/module_utils/common/text/formatters.py +20 -4
  94. ansible/module_utils/common/validation.py +33 -25
  95. ansible/module_utils/compat/paramiko.py +6 -1
  96. ansible/module_utils/compat/selinux.py +2 -2
  97. ansible/module_utils/connection.py +8 -24
  98. ansible/module_utils/csharp/Ansible.Become.cs +14 -25
  99. ansible/module_utils/csharp/Ansible.Process.cs +1 -1
  100. ansible/module_utils/distro/__init__.py +1 -1
  101. ansible/module_utils/distro/_distro.py +8 -4
  102. ansible/module_utils/facts/collector.py +2 -0
  103. ansible/module_utils/facts/default_collectors.py +3 -1
  104. ansible/module_utils/facts/hardware/aix.py +54 -52
  105. ansible/module_utils/facts/hardware/darwin.py +37 -34
  106. ansible/module_utils/facts/hardware/freebsd.py +55 -15
  107. ansible/module_utils/facts/hardware/hpux.py +3 -0
  108. ansible/module_utils/facts/hardware/linux.py +101 -57
  109. ansible/module_utils/facts/hardware/netbsd.py +3 -0
  110. ansible/module_utils/facts/hardware/openbsd.py +4 -1
  111. ansible/module_utils/facts/hardware/sunos.py +7 -1
  112. ansible/module_utils/facts/network/aix.py +16 -17
  113. ansible/module_utils/facts/network/fc_wwn.py +4 -1
  114. ansible/module_utils/facts/network/hpux.py +21 -4
  115. ansible/module_utils/facts/network/iscsi.py +7 -8
  116. ansible/module_utils/facts/network/linux.py +0 -2
  117. ansible/module_utils/facts/other/facter.py +9 -4
  118. ansible/module_utils/facts/other/ohai.py +5 -5
  119. ansible/module_utils/facts/packages.py +49 -7
  120. ansible/module_utils/facts/sysctl.py +33 -31
  121. ansible/module_utils/facts/system/distribution.py +1 -1
  122. ansible/module_utils/facts/system/local.py +12 -22
  123. ansible/module_utils/facts/system/service_mgr.py +3 -1
  124. ansible/module_utils/facts/system/systemd.py +47 -0
  125. ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 +1 -1
  126. ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 +1 -1
  127. ansible/module_utils/splitter.py +1 -1
  128. ansible/modules/add_host.py +1 -1
  129. ansible/modules/apt.py +43 -32
  130. ansible/modules/apt_key.py +6 -6
  131. ansible/modules/apt_repository.py +23 -14
  132. ansible/modules/assemble.py +7 -2
  133. ansible/modules/assert.py +4 -4
  134. ansible/modules/blockinfile.py +3 -6
  135. ansible/modules/command.py +1 -1
  136. ansible/modules/copy.py +4 -4
  137. ansible/modules/cron.py +13 -10
  138. ansible/modules/deb822_repository.py +16 -17
  139. ansible/modules/debconf.py +9 -9
  140. ansible/modules/debug.py +1 -1
  141. ansible/modules/dnf.py +79 -164
  142. ansible/modules/dnf5.py +54 -29
  143. ansible/modules/dpkg_selections.py +2 -2
  144. ansible/modules/expect.py +2 -2
  145. ansible/modules/fetch.py +2 -2
  146. ansible/modules/file.py +5 -3
  147. ansible/modules/find.py +40 -12
  148. ansible/modules/gather_facts.py +4 -2
  149. ansible/modules/get_url.py +29 -24
  150. ansible/modules/git.py +35 -35
  151. ansible/modules/group.py +71 -1
  152. ansible/modules/hostname.py +2 -4
  153. ansible/modules/include_vars.py +5 -5
  154. ansible/modules/iptables.py +13 -16
  155. ansible/modules/known_hosts.py +16 -13
  156. ansible/modules/lineinfile.py +1 -4
  157. ansible/modules/meta.py +6 -1
  158. ansible/modules/mount_facts.py +651 -0
  159. ansible/modules/package_facts.py +63 -80
  160. ansible/modules/pause.py +4 -3
  161. ansible/modules/pip.py +14 -14
  162. ansible/modules/replace.py +1 -4
  163. ansible/modules/rpm_key.py +31 -11
  164. ansible/modules/service.py +8 -8
  165. ansible/modules/service_facts.py +20 -5
  166. ansible/modules/set_stats.py +1 -1
  167. ansible/modules/setup.py +3 -3
  168. ansible/modules/stat.py +3 -3
  169. ansible/modules/subversion.py +1 -1
  170. ansible/modules/systemd.py +16 -10
  171. ansible/modules/systemd_service.py +16 -10
  172. ansible/modules/sysvinit.py +4 -4
  173. ansible/modules/unarchive.py +35 -22
  174. ansible/modules/uri.py +24 -18
  175. ansible/modules/user.py +145 -12
  176. ansible/modules/validate_argument_spec.py +3 -3
  177. ansible/modules/wait_for_connection.py +2 -1
  178. ansible/modules/yum_repository.py +136 -179
  179. ansible/parsing/dataloader.py +2 -2
  180. ansible/parsing/mod_args.py +11 -10
  181. ansible/parsing/vault/__init__.py +8 -3
  182. ansible/parsing/yaml/constructor.py +10 -8
  183. ansible/parsing/yaml/objects.py +1 -1
  184. ansible/playbook/base.py +12 -23
  185. ansible/playbook/helpers.py +4 -0
  186. ansible/playbook/loop_control.py +8 -0
  187. ansible/playbook/play.py +4 -22
  188. ansible/playbook/play_context.py +0 -16
  189. ansible/playbook/playbook_include.py +2 -2
  190. ansible/playbook/role/__init__.py +2 -2
  191. ansible/plugins/__init__.py +2 -0
  192. ansible/plugins/action/__init__.py +7 -9
  193. ansible/plugins/action/dnf.py +7 -5
  194. ansible/plugins/action/package.py +5 -4
  195. ansible/plugins/action/reboot.py +2 -2
  196. ansible/plugins/become/__init__.py +1 -1
  197. ansible/plugins/callback/__init__.py +44 -3
  198. ansible/plugins/callback/default.py +1 -1
  199. ansible/plugins/cliconf/__init__.py +1 -1
  200. ansible/plugins/connection/paramiko_ssh.py +2 -80
  201. ansible/plugins/connection/psrp.py +33 -82
  202. ansible/plugins/connection/ssh.py +0 -8
  203. ansible/plugins/connection/winrm.py +46 -1
  204. ansible/plugins/doc_fragments/connection_pipelining.py +2 -2
  205. ansible/plugins/doc_fragments/constructed.py +10 -10
  206. ansible/plugins/doc_fragments/default_callback.py +8 -8
  207. ansible/plugins/doc_fragments/files.py +5 -5
  208. ansible/plugins/doc_fragments/inventory_cache.py +2 -2
  209. ansible/plugins/doc_fragments/result_format_callback.py +6 -6
  210. ansible/plugins/doc_fragments/return_common.py +1 -1
  211. ansible/plugins/doc_fragments/shell_common.py +2 -10
  212. ansible/plugins/doc_fragments/shell_windows.py +0 -9
  213. ansible/plugins/doc_fragments/url.py +2 -2
  214. ansible/plugins/doc_fragments/url_windows.py +4 -5
  215. ansible/plugins/doc_fragments/validate.py +1 -1
  216. ansible/plugins/filter/core.py +2 -0
  217. ansible/plugins/filter/human_to_bytes.yml +9 -0
  218. ansible/plugins/filter/password_hash.yml +1 -1
  219. ansible/plugins/filter/strftime.yml +1 -1
  220. ansible/plugins/filter/to_nice_json.yml +7 -3
  221. ansible/plugins/filter/to_uuid.yml +1 -1
  222. ansible/plugins/inventory/script.py +1 -1
  223. ansible/plugins/list.py +1 -1
  224. ansible/plugins/loader.py +0 -11
  225. ansible/plugins/lookup/config.py +1 -1
  226. ansible/plugins/lookup/csvfile.py +21 -9
  227. ansible/plugins/lookup/env.py +8 -9
  228. ansible/plugins/lookup/ini.py +10 -1
  229. ansible/plugins/lookup/random_choice.py +2 -2
  230. ansible/plugins/lookup/url.py +7 -2
  231. ansible/plugins/shell/__init__.py +15 -20
  232. ansible/plugins/shell/powershell.py +9 -6
  233. ansible/plugins/strategy/__init__.py +16 -7
  234. ansible/plugins/test/core.py +23 -1
  235. ansible/plugins/test/issubset.yml +1 -1
  236. ansible/plugins/test/subset.yml +1 -1
  237. ansible/plugins/test/timedout.yml +20 -0
  238. ansible/plugins/test/vault_encrypted.yml +6 -6
  239. ansible/plugins/test/vaulted_file.yml +19 -0
  240. ansible/release.py +2 -2
  241. ansible/template/__init__.py +3 -8
  242. ansible/utils/collection_loader/_collection_finder.py +23 -55
  243. ansible/utils/display.py +44 -31
  244. ansible/utils/jsonrpc.py +1 -1
  245. ansible/utils/listify.py +1 -5
  246. ansible/utils/path.py +3 -0
  247. ansible/utils/vars.py +18 -27
  248. ansible/vars/manager.py +7 -150
  249. ansible/vars/plugins.py +1 -1
  250. ansible_core-2.18.0.dist-info/Apache-License.txt +202 -0
  251. {ansible_core-2.17.6rc1.dist-info → ansible_core-2.18.0.dist-info}/METADATA +36 -23
  252. ansible_core-2.18.0.dist-info/MIT-license.txt +14 -0
  253. ansible_core-2.18.0.dist-info/PSF-license.txt +48 -0
  254. {ansible_core-2.17.6rc1.dist-info → ansible_core-2.18.0.dist-info}/RECORD +316 -311
  255. {ansible_core-2.17.6rc1.dist-info → ansible_core-2.18.0.dist-info}/entry_points.txt +1 -1
  256. ansible_core-2.18.0.dist-info/simplified_bsd.txt +8 -0
  257. ansible_test/_data/completion/docker.txt +7 -7
  258. ansible_test/_data/completion/remote.txt +5 -4
  259. ansible_test/_data/completion/windows.txt +4 -4
  260. ansible_test/_data/requirements/ansible-test.txt +1 -2
  261. ansible_test/_data/requirements/constraints.txt +1 -2
  262. ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
  263. ansible_test/_data/requirements/sanity.changelog.in +1 -1
  264. ansible_test/_data/requirements/sanity.changelog.txt +4 -4
  265. ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
  266. ansible_test/_data/requirements/sanity.import.txt +1 -1
  267. ansible_test/_data/requirements/sanity.integration-aliases.txt +1 -1
  268. ansible_test/_data/requirements/sanity.pep8.txt +1 -1
  269. ansible_test/_data/requirements/sanity.pylint.txt +6 -8
  270. ansible_test/_data/requirements/sanity.runtime-metadata.txt +2 -2
  271. ansible_test/_data/requirements/sanity.validate-modules.txt +3 -3
  272. ansible_test/_data/requirements/sanity.yamllint.in +1 -0
  273. ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
  274. ansible_test/_internal/ansible_util.py +8 -35
  275. ansible_test/_internal/ci/azp.py +1 -1
  276. ansible_test/_internal/classification/__init__.py +0 -2
  277. ansible_test/_internal/cli/parsers/key_value_parsers.py +3 -0
  278. ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -1
  279. ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
  280. ansible_test/_internal/commands/integration/cloud/nios.py +1 -1
  281. ansible_test/_internal/commands/sanity/__init__.py +96 -19
  282. ansible_test/_internal/commands/sanity/pylint.py +20 -24
  283. ansible_test/_internal/completion.py +2 -0
  284. ansible_test/_internal/constants.py +0 -1
  285. ansible_test/_internal/coverage_util.py +1 -2
  286. ansible_test/_internal/docker_util.py +1 -1
  287. ansible_test/_internal/encoding.py +4 -4
  288. ansible_test/_internal/host_configs.py +10 -0
  289. ansible_test/_internal/host_profiles.py +9 -13
  290. ansible_test/_internal/pypi_proxy.py +1 -1
  291. ansible_test/_internal/python_requirements.py +5 -14
  292. ansible_test/_internal/timeout.py +1 -1
  293. ansible_test/_internal/util.py +40 -0
  294. ansible_test/_internal/util_common.py +5 -1
  295. ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.json +3 -1
  296. ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +6 -3
  297. ansible_test/_util/controller/sanity/code-smell/empty-init.json +0 -2
  298. ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +5 -0
  299. ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +5 -0
  300. ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +5 -0
  301. ansible_test/_util/controller/sanity/pylint/config/collection.cfg +6 -0
  302. ansible_test/_util/controller/sanity/pylint/config/default.cfg +6 -0
  303. ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -19
  304. ansible_test/_util/controller/sanity/shellcheck/exclude.txt +1 -0
  305. ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +67 -2
  306. ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +27 -5
  307. ansible_test/_util/target/cli/ansible_test_cli_stub.py +0 -0
  308. ansible_test/_util/target/common/constants.py +2 -2
  309. ansible_test/_util/target/injector/python.py +5 -0
  310. ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +6 -0
  311. ansible_test/_util/target/sanity/import/importer.py +1 -1
  312. ansible_test/_util/target/setup/bootstrap.sh +6 -17
  313. ansible_test/_util/target/setup/requirements.py +18 -24
  314. ansible_test/config/config.yml +1 -1
  315. ansible_core-2.17.6rc1.data/scripts/ansible-test +0 -44
  316. ansible_test/_data/requirements/sanity.mypy.in +0 -10
  317. ansible_test/_data/requirements/sanity.mypy.txt +0 -18
  318. ansible_test/_internal/commands/sanity/mypy.py +0 -274
  319. ansible_test/_util/controller/sanity/mypy/ansible-core.ini +0 -116
  320. ansible_test/_util/controller/sanity/mypy/ansible-test.ini +0 -27
  321. ansible_test/_util/controller/sanity/mypy/modules.ini +0 -92
  322. ansible_test/_util/controller/sanity/mypy/packaging.ini +0 -20
  323. {ansible_core-2.17.6rc1.dist-info → ansible_core-2.18.0.dist-info}/COPYING +0 -0
  324. {ansible_core-2.17.6rc1.dist-info → ansible_core-2.18.0.dist-info}/WHEEL +0 -0
  325. {ansible_core-2.17.6rc1.dist-info → ansible_core-2.18.0.dist-info}/top_level.txt +0 -0
@@ -43,7 +43,6 @@ from ...util import (
43
43
 
44
44
  from ...util_common import (
45
45
  run_command,
46
- process_scoped_temporary_file,
47
46
  )
48
47
 
49
48
  from ...ansible_util import (
@@ -87,7 +86,7 @@ class PylintTest(SanitySingleVersion):
87
86
  return [target for target in targets if os.path.splitext(target.path)[1] == '.py' or is_subdir(target.path, 'bin')]
88
87
 
89
88
  def test(self, args: SanityConfig, targets: SanityTargets, python: PythonConfig) -> TestResult:
90
- min_python_version_db_path = self.create_min_python_db(args, targets.targets)
89
+ target_paths = set(target.path for target in self.filter_remote_targets(list(targets.targets)))
91
90
 
92
91
  plugin_dir = os.path.join(SANITY_ROOT, 'pylint', 'plugins')
93
92
  plugin_names = sorted(p[0] for p in [
@@ -115,7 +114,13 @@ class PylintTest(SanitySingleVersion):
115
114
  def add_context(available_paths: set[str], context_name: str, context_filter: c.Callable[[str], bool]) -> None:
116
115
  """Add the specified context to the context list, consuming available paths that match the given context filter."""
117
116
  filtered_paths = set(p for p in available_paths if context_filter(p))
118
- contexts.append((context_name, sorted(filtered_paths)))
117
+
118
+ if selected_paths := sorted(path for path in filtered_paths if path in target_paths):
119
+ contexts.append((context_name, True, selected_paths))
120
+
121
+ if selected_paths := sorted(path for path in filtered_paths if path not in target_paths):
122
+ contexts.append((context_name, False, selected_paths))
123
+
119
124
  available_paths -= filtered_paths
120
125
 
121
126
  def filter_path(path_filter: str = None) -> c.Callable[[str], bool]:
@@ -166,12 +171,12 @@ class PylintTest(SanitySingleVersion):
166
171
 
167
172
  test_start = datetime.datetime.now(tz=datetime.timezone.utc)
168
173
 
169
- for context, context_paths in sorted(contexts):
174
+ for context, is_target, context_paths in sorted(contexts):
170
175
  if not context_paths:
171
176
  continue
172
177
 
173
178
  context_start = datetime.datetime.now(tz=datetime.timezone.utc)
174
- messages += self.pylint(args, context, context_paths, plugin_dir, plugin_names, python, collection_detail, min_python_version_db_path)
179
+ messages += self.pylint(args, context, is_target, context_paths, plugin_dir, plugin_names, python, collection_detail)
175
180
  context_end = datetime.datetime.now(tz=datetime.timezone.utc)
176
181
 
177
182
  context_times.append('%s: %d (%s)' % (context, len(context_paths), context_end - context_start))
@@ -202,32 +207,16 @@ class PylintTest(SanitySingleVersion):
202
207
 
203
208
  return SanitySuccess(self.name)
204
209
 
205
- def create_min_python_db(self, args: SanityConfig, targets: t.Iterable[TestTarget]) -> str:
206
- """Create a database of target file paths and their minimum required Python version, returning the path to the database."""
207
- target_paths = set(target.path for target in self.filter_remote_targets(list(targets)))
208
- controller_min_version = CONTROLLER_PYTHON_VERSIONS[0]
209
- target_min_version = REMOTE_ONLY_PYTHON_VERSIONS[0]
210
- min_python_versions = {
211
- os.path.abspath(target.path): target_min_version if target.path in target_paths else controller_min_version for target in targets
212
- }
213
-
214
- min_python_version_db_path = process_scoped_temporary_file(args)
215
-
216
- with open(min_python_version_db_path, 'w') as database_file:
217
- json.dump(min_python_versions, database_file)
218
-
219
- return min_python_version_db_path
220
-
221
210
  @staticmethod
222
211
  def pylint(
223
212
  args: SanityConfig,
224
213
  context: str,
214
+ is_target: bool,
225
215
  paths: list[str],
226
216
  plugin_dir: str,
227
217
  plugin_names: list[str],
228
218
  python: PythonConfig,
229
219
  collection_detail: CollectionDetail,
230
- min_python_version_db_path: str,
231
220
  ) -> list[dict[str, str]]:
232
221
  """Run pylint using the config specified by the context on the specified paths."""
233
222
  rcfile = os.path.join(SANITY_ROOT, 'pylint', 'config', context.split('/')[0] + '.cfg')
@@ -249,6 +238,13 @@ class PylintTest(SanitySingleVersion):
249
238
  disable_plugins = set(i.strip() for i in config.get('disable-plugins', '').split(',') if i)
250
239
  load_plugins = set(plugin_names + ['pylint.extensions.mccabe']) - disable_plugins
251
240
 
241
+ if is_target:
242
+ context_label = 'target'
243
+ min_python_version = REMOTE_ONLY_PYTHON_VERSIONS[0]
244
+ else:
245
+ context_label = 'controller'
246
+ min_python_version = CONTROLLER_PYTHON_VERSIONS[0]
247
+
252
248
  cmd = [
253
249
  python.path,
254
250
  '-m', 'pylint',
@@ -259,7 +255,7 @@ class PylintTest(SanitySingleVersion):
259
255
  '--rcfile', rcfile,
260
256
  '--output-format', 'json',
261
257
  '--load-plugins', ','.join(sorted(load_plugins)),
262
- '--min-python-version-db', min_python_version_db_path,
258
+ '--py-version', min_python_version,
263
259
  ] + paths # fmt: skip
264
260
 
265
261
  if data_context().content.collection:
@@ -286,7 +282,7 @@ class PylintTest(SanitySingleVersion):
286
282
  env.update(PYLINTHOME=pylint_home)
287
283
 
288
284
  if paths:
289
- display.info('Checking %d file(s) in context "%s" with config: %s' % (len(paths), context, rcfile), verbosity=1)
285
+ display.info(f'Checking {len(paths)} file(s) in context {context!r} ({context_label}) with config: {rcfile}', verbosity=1)
290
286
 
291
287
  try:
292
288
  stdout, stderr = run_command(args, cmd, env=env, capture=True)
@@ -246,6 +246,8 @@ class PosixRemoteCompletionConfig(RemoteCompletionConfig, PythonCompletionConfig
246
246
  class WindowsRemoteCompletionConfig(RemoteCompletionConfig):
247
247
  """Configuration for remote Windows platforms."""
248
248
 
249
+ connection: str = ''
250
+
249
251
 
250
252
  TCompletionConfig = t.TypeVar('TCompletionConfig', bound=CompletionConfig)
251
253
 
@@ -37,7 +37,6 @@ SECCOMP_CHOICES = [
37
37
  ANSIBLE_BIN_SYMLINK_MAP = {
38
38
  'ansible': '../lib/ansible/cli/adhoc.py',
39
39
  'ansible-config': '../lib/ansible/cli/config.py',
40
- 'ansible-connection': '../lib/ansible/cli/scripts/ansible_connection_cli_stub.py',
41
40
  'ansible-console': '../lib/ansible/cli/console.py',
42
41
  'ansible-doc': '../lib/ansible/cli/doc.py',
43
42
  'ansible-galaxy': '../lib/ansible/cli/galaxy.py',
@@ -69,8 +69,7 @@ class CoverageVersion:
69
69
 
70
70
  COVERAGE_VERSIONS = (
71
71
  # IMPORTANT: Keep this in sync with the ansible-test.txt requirements file.
72
- CoverageVersion('7.3.2', 7, (3, 8), (3, 12)),
73
- CoverageVersion('6.5.0', 7, (3, 7), (3, 7)),
72
+ CoverageVersion('7.6.1', 7, (3, 8), (3, 13)),
74
73
  )
75
74
  """
76
75
  This tuple specifies the coverage version to use for Python version ranges.
@@ -49,7 +49,7 @@ DOCKER_COMMANDS = [
49
49
  'podman',
50
50
  ]
51
51
 
52
- UTILITY_IMAGE = 'quay.io/ansible/ansible-test-utility-container:2.0.0'
52
+ UTILITY_IMAGE = 'quay.io/ansible/ansible-test-utility-container:3.1.0'
53
53
 
54
54
  # Max number of open files in a docker container.
55
55
  # Passed with --ulimit option to the docker run command.
@@ -6,17 +6,17 @@ import typing as t
6
6
  ENCODING = 'utf-8'
7
7
 
8
8
 
9
- def to_optional_bytes(value: t.Optional[t.AnyStr], errors: str = 'strict') -> t.Optional[bytes]:
9
+ def to_optional_bytes(value: t.Optional[str | bytes], errors: str = 'strict') -> t.Optional[bytes]:
10
10
  """Return the given value as bytes encoded using UTF-8 if not already bytes, or None if the value is None."""
11
11
  return None if value is None else to_bytes(value, errors)
12
12
 
13
13
 
14
- def to_optional_text(value: t.Optional[t.AnyStr], errors: str = 'strict') -> t.Optional[str]:
14
+ def to_optional_text(value: t.Optional[str | bytes], errors: str = 'strict') -> t.Optional[str]:
15
15
  """Return the given value as text decoded using UTF-8 if not already text, or None if the value is None."""
16
16
  return None if value is None else to_text(value, errors)
17
17
 
18
18
 
19
- def to_bytes(value: t.AnyStr, errors: str = 'strict') -> bytes:
19
+ def to_bytes(value: str | bytes, errors: str = 'strict') -> bytes:
20
20
  """Return the given value as bytes encoded using UTF-8 if not already bytes."""
21
21
  if isinstance(value, bytes):
22
22
  return value
@@ -27,7 +27,7 @@ def to_bytes(value: t.AnyStr, errors: str = 'strict') -> bytes:
27
27
  raise Exception('value is not bytes or text: %s' % type(value))
28
28
 
29
29
 
30
- def to_text(value: t.AnyStr, errors: str = 'strict') -> str:
30
+ def to_text(value: str | bytes, errors: str = 'strict') -> str:
31
31
  """Return the given value as text decoded using UTF-8 if not already text."""
32
32
  if isinstance(value, bytes):
33
33
  return value.decode(ENCODING, errors)
@@ -399,10 +399,20 @@ class WindowsConfig(HostConfig, metaclass=abc.ABCMeta):
399
399
  class WindowsRemoteConfig(RemoteConfig, WindowsConfig):
400
400
  """Configuration for a remote Windows host."""
401
401
 
402
+ connection: t.Optional[str] = None
403
+
402
404
  def get_defaults(self, context: HostContext) -> WindowsRemoteCompletionConfig:
403
405
  """Return the default settings."""
404
406
  return filter_completion(windows_completion()).get(self.name) or windows_completion().get(self.platform)
405
407
 
408
+ def apply_defaults(self, context: HostContext, defaults: CompletionConfig) -> None:
409
+ """Apply default settings."""
410
+ assert isinstance(defaults, WindowsRemoteCompletionConfig)
411
+
412
+ super().apply_defaults(context, defaults)
413
+
414
+ self.connection = self.connection or defaults.connection
415
+
406
416
 
407
417
  @dataclasses.dataclass
408
418
  class WindowsInventoryConfig(InventoryConfig, WindowsConfig):
@@ -56,6 +56,7 @@ from .util import (
56
56
  InternalError,
57
57
  HostConnectionError,
58
58
  ANSIBLE_TEST_TARGET_ROOT,
59
+ WINDOWS_CONNECTION_VARIABLES,
59
60
  )
60
61
 
61
62
  from .util_common import (
@@ -1367,23 +1368,18 @@ class WindowsRemoteProfile(RemoteProfile[WindowsRemoteConfig]):
1367
1368
  connection = core_ci.connection
1368
1369
 
1369
1370
  variables: dict[str, t.Optional[t.Union[str, int]]] = dict(
1370
- ansible_connection='winrm',
1371
- ansible_pipelining='yes',
1372
- ansible_winrm_server_cert_validation='ignore',
1373
1371
  ansible_host=connection.hostname,
1374
- ansible_port=connection.port,
1372
+ # ansible_port is intentionally not set using connection.port -- connection-specific variables can set this instead
1375
1373
  ansible_user=connection.username,
1376
- ansible_password=connection.password,
1377
- ansible_ssh_private_key_file=core_ci.ssh_key.key,
1374
+ ansible_ssh_private_key_file=core_ci.ssh_key.key, # required for scenarios which change the connection plugin to SSH
1375
+ ansible_test_connection_password=connection.password, # required for scenarios which change the connection plugin to require a password
1378
1376
  )
1379
1377
 
1380
- # HACK: force 2016 to use NTLM + HTTP message encryption
1381
- if self.config.version == '2016':
1382
- variables.update(
1383
- ansible_winrm_transport='ntlm',
1384
- ansible_winrm_scheme='http',
1385
- ansible_port='5985',
1386
- )
1378
+ variables.update(ansible_connection=self.config.connection.split('+')[0])
1379
+ variables.update(WINDOWS_CONNECTION_VARIABLES[self.config.connection])
1380
+
1381
+ if variables.pop('use_password'):
1382
+ variables.update(ansible_password=connection.password)
1387
1383
 
1388
1384
  return variables
1389
1385
 
@@ -69,7 +69,7 @@ def run_pypi_proxy(args: EnvironmentConfig, targets_use_pypi: bool) -> None:
69
69
  display.warning('Unable to use the PyPI proxy because Docker is not available. Installation of packages using `pip` may fail.')
70
70
  return
71
71
 
72
- image = 'quay.io/ansible/pypi-test-container:3.1.0'
72
+ image = 'quay.io/ansible/pypi-test-container:3.2.0'
73
73
  port = 3141
74
74
 
75
75
  run_support_container(
@@ -112,6 +112,8 @@ class PipBootstrap(PipCommand):
112
112
 
113
113
  pip_version: str
114
114
  packages: list[str]
115
+ setuptools: bool
116
+ wheel: bool
115
117
 
116
118
 
117
119
  # Entry Points
@@ -177,6 +179,8 @@ def collect_bootstrap(python: PythonConfig) -> list[PipCommand]:
177
179
  bootstrap = PipBootstrap(
178
180
  pip_version=pip_version,
179
181
  packages=packages,
182
+ setuptools=False,
183
+ wheel=False,
180
184
  )
181
185
 
182
186
  return [bootstrap]
@@ -218,17 +222,6 @@ def collect_requirements(
218
222
  # removing them reduces the size of environments cached in containers
219
223
  uninstall_packages = list(get_venv_packages(python))
220
224
 
221
- if not minimize:
222
- # installed packages may have run-time dependencies on setuptools
223
- uninstall_packages.remove('setuptools')
224
-
225
- # hack to allow the package-data sanity test to keep wheel in the venv
226
- install_commands = [command for command in commands if isinstance(command, PipInstall)]
227
- install_wheel = any(install.has_package('wheel') for install in install_commands)
228
-
229
- if install_wheel:
230
- uninstall_packages.remove('wheel')
231
-
232
225
  commands.extend(collect_uninstall(packages=uninstall_packages))
233
226
 
234
227
  return commands
@@ -412,9 +405,7 @@ def get_venv_packages(python: PythonConfig) -> dict[str, str]:
412
405
  # See: https://github.com/ansible/base-test-container/blob/main/files/installer.py
413
406
 
414
407
  default_packages = dict(
415
- pip='23.1.2',
416
- setuptools='67.7.2',
417
- wheel='0.37.1',
408
+ pip='24.2',
418
409
  )
419
410
 
420
411
  override_packages: dict[str, dict[str, str]] = {
@@ -118,7 +118,7 @@ def configure_test_timeout(args: TestConfig) -> None:
118
118
 
119
119
  raise TimeoutExpiredError(f'Tests aborted after exceeding the {timeout.duration} minute time limit.')
120
120
 
121
- def timeout_waiter(timeout_seconds: int) -> None:
121
+ def timeout_waiter(timeout_seconds: float) -> None:
122
122
  """Background thread which will kill the current process if the timeout elapses."""
123
123
  time.sleep(timeout_seconds)
124
124
  os.kill(os.getpid(), signal.SIGUSR1)
@@ -134,6 +134,46 @@ class Architecture:
134
134
  REMOTE_ARCHITECTURES = list(value for key, value in Architecture.__dict__.items() if not key.startswith('__'))
135
135
 
136
136
 
137
+ WINDOWS_CONNECTION_VARIABLES: dict[str, t.Any] = {
138
+ 'psrp+http': dict(
139
+ ansible_port=5985,
140
+ ansible_psrp_protocol='http',
141
+ use_password=True,
142
+ ),
143
+ 'psrp+https': dict(
144
+ ansible_port=5986,
145
+ ansible_psrp_protocol='https',
146
+ ansible_psrp_cert_validation='ignore',
147
+ use_password=True,
148
+ ),
149
+ 'ssh+key': dict(
150
+ ansible_port=22,
151
+ ansible_shell_type='powershell',
152
+ use_password=False,
153
+ ),
154
+ 'ssh+password': dict(
155
+ ansible_port=22,
156
+ ansible_shell_type='powershell',
157
+ use_password=True,
158
+ ),
159
+ 'winrm+http': dict(
160
+ ansible_port=5985,
161
+ ansible_winrm_scheme='http',
162
+ ansible_winrm_transport='ntlm',
163
+ use_password=True,
164
+ ),
165
+ 'winrm+https': dict(
166
+ ansible_port=5986,
167
+ ansible_winrm_scheme='https',
168
+ ansible_winrm_server_cert_validation='ignore',
169
+ use_password=True,
170
+ ),
171
+ }
172
+ """Dictionary of Windows connection types and variables required to use them."""
173
+
174
+ WINDOWS_CONNECTIONS = list(WINDOWS_CONNECTION_VARIABLES)
175
+
176
+
137
177
  def is_valid_identifier(value: str) -> bool:
138
178
  """Return True if the given value is a valid non-keyword Python identifier, otherwise return False."""
139
179
  return value.isidentifier() and not keyword.iskeyword(value)
@@ -269,7 +269,10 @@ def named_temporary_file(args: CommonConfig, prefix: str, suffix: str, directory
269
269
  tempfile_fd.write(to_bytes(content))
270
270
  tempfile_fd.flush()
271
271
 
272
- yield tempfile_fd.name
272
+ try:
273
+ yield tempfile_fd.name
274
+ finally:
275
+ pass
273
276
 
274
277
 
275
278
  def write_json_test_results(
@@ -300,6 +303,7 @@ def get_injector_path() -> str:
300
303
  injector_names = sorted(list(ANSIBLE_BIN_SYMLINK_MAP) + [
301
304
  'importer.py',
302
305
  'pytest',
306
+ 'ansible_connection_cli_stub.py',
303
307
  ])
304
308
 
305
309
  scripts = (
@@ -7,7 +7,9 @@
7
7
  "plugins/action/"
8
8
  ],
9
9
  "extensions": [
10
- ".py"
10
+ ".py",
11
+ ".yml",
12
+ ".yaml"
11
13
  ],
12
14
  "output": "path-message"
13
15
  }
@@ -28,13 +28,13 @@ def main():
28
28
  module_names.add(full_name)
29
29
 
30
30
  for path in paths:
31
- full_name = get_full_name(path, action_prefixes)
31
+ full_name = get_full_name(path, action_prefixes, extensions=('.py',))
32
32
 
33
33
  if full_name and full_name not in module_names:
34
34
  print('%s: action plugin has no matching module to provide documentation' % path)
35
35
 
36
36
 
37
- def get_full_name(path, prefixes):
37
+ def get_full_name(path: str, prefixes: dict[str, bool], extensions: tuple[str] | None = None) -> str | None:
38
38
  """Return the full name of the plugin at the given path by matching against the given path prefixes, or None if no match is found."""
39
39
  for prefix, flat in prefixes.items():
40
40
  if path.startswith(prefix):
@@ -45,13 +45,16 @@ def get_full_name(path, prefixes):
45
45
  else:
46
46
  full_name = relative_path
47
47
 
48
- full_name = os.path.splitext(full_name)[0]
48
+ full_name, file_ext = os.path.splitext(full_name)
49
49
 
50
50
  name = os.path.basename(full_name)
51
51
 
52
52
  if name == '__init__':
53
53
  return None
54
54
 
55
+ if extensions and file_ext not in extensions:
56
+ return None
57
+
55
58
  if name.startswith('_'):
56
59
  name = name[1:]
57
60
 
@@ -1,9 +1,7 @@
1
1
  {
2
2
  "prefixes": [
3
3
  "lib/ansible/modules/",
4
- "lib/ansible/module_utils/",
5
4
  "plugins/modules/",
6
- "plugins/module_utils/",
7
5
  "test/units/",
8
6
  "tests/unit/"
9
7
  ],
@@ -3,6 +3,10 @@
3
3
  disable=
4
4
  consider-using-f-string, # Python 2.x support still required
5
5
  cyclic-import, # consistent results require running with --jobs 1 and testing all files
6
+ deprecated-argument, # results vary by Python version
7
+ deprecated-attribute, # results vary by Python version
8
+ deprecated-class, # results vary by Python version
9
+ deprecated-decorator, # results vary by Python version
6
10
  deprecated-method, # results vary by Python version
7
11
  deprecated-module, # results vary by Python version
8
12
  duplicate-code, # consistent results require running with --jobs 1 and testing all files
@@ -20,6 +24,7 @@ disable=
20
24
  too-many-nested-blocks,
21
25
  too-many-return-statements,
22
26
  too-many-statements,
27
+ too-many-positional-arguments,
23
28
  use-dict-literal, # ignoring as a common style issue
24
29
  useless-return, # complains about returning None when the return type is optional
25
30
 
@@ -3,6 +3,10 @@
3
3
  disable=
4
4
  consider-using-f-string, # many occurrences
5
5
  cyclic-import, # consistent results require running with --jobs 1 and testing all files
6
+ deprecated-argument, # results vary by Python version
7
+ deprecated-attribute, # results vary by Python version
8
+ deprecated-class, # results vary by Python version
9
+ deprecated-decorator, # results vary by Python version
6
10
  deprecated-method, # results vary by Python version
7
11
  deprecated-module, # results vary by Python version
8
12
  duplicate-code, # consistent results require running with --jobs 1 and testing all files
@@ -18,6 +22,7 @@ disable=
18
22
  too-many-nested-blocks,
19
23
  too-many-return-statements,
20
24
  too-many-statements,
25
+ too-many-positional-arguments,
21
26
  use-dict-literal, # ignoring as a common style issue
22
27
  unspecified-encoding, # always run with UTF-8 encoding enforced
23
28
  useless-return, # complains about returning None when the return type is optional
@@ -3,6 +3,10 @@
3
3
  disable=
4
4
  consider-using-f-string, # many occurrences
5
5
  cyclic-import, # consistent results require running with --jobs 1 and testing all files
6
+ deprecated-argument, # results vary by Python version
7
+ deprecated-attribute, # results vary by Python version
8
+ deprecated-class, # results vary by Python version
9
+ deprecated-decorator, # results vary by Python version
6
10
  deprecated-method, # results vary by Python version
7
11
  deprecated-module, # results vary by Python version
8
12
  duplicate-code, # consistent results require running with --jobs 1 and testing all files
@@ -17,6 +21,7 @@ disable=
17
21
  too-many-nested-blocks,
18
22
  too-many-return-statements,
19
23
  too-many-statements,
24
+ too-many-positional-arguments,
20
25
  use-dict-literal, # ignoring as a common style issue
21
26
  unspecified-encoding, # always run with UTF-8 encoding enforced
22
27
  useless-return, # complains about returning None when the return type is optional
@@ -30,7 +30,11 @@ disable=
30
30
  consider-using-max-builtin,
31
31
  consider-using-min-builtin,
32
32
  cyclic-import, # consistent results require running with --jobs 1 and testing all files
33
+ deprecated-argument, # results vary by Python version
34
+ deprecated-attribute, # results vary by Python version
35
+ deprecated-class, # results vary by Python version
33
36
  deprecated-comment, # custom plugin only used by ansible-core, not collections
37
+ deprecated-decorator, # results vary by Python version
34
38
  deprecated-method, # results vary by Python version
35
39
  deprecated-module, # results vary by Python version
36
40
  duplicate-code, # consistent results require running with --jobs 1 and testing all files
@@ -69,6 +73,7 @@ disable=
69
73
  pointless-statement,
70
74
  pointless-string-statement,
71
75
  possibly-unused-variable,
76
+ possibly-used-before-assignment,
72
77
  protected-access,
73
78
  raise-missing-from, # Python 2.x does not support raise from
74
79
  redefined-argument-from-local,
@@ -97,6 +102,7 @@ disable=
97
102
  too-many-public-methods,
98
103
  too-many-return-statements,
99
104
  too-many-statements,
105
+ too-many-positional-arguments,
100
106
  try-except-raise,
101
107
  unbalanced-tuple-unpacking,
102
108
  undefined-loop-variable,
@@ -28,6 +28,10 @@ disable=
28
28
  consider-using-max-builtin,
29
29
  consider-using-min-builtin,
30
30
  cyclic-import, # consistent results require running with --jobs 1 and testing all files
31
+ deprecated-argument, # results vary by Python version
32
+ deprecated-attribute, # results vary by Python version
33
+ deprecated-class, # results vary by Python version
34
+ deprecated-decorator, # results vary by Python version
31
35
  deprecated-method, # results vary by Python version
32
36
  deprecated-module, # results vary by Python version
33
37
  duplicate-code, # consistent results require running with --jobs 1 and testing all files
@@ -63,6 +67,7 @@ disable=
63
67
  not-an-iterable,
64
68
  not-callable,
65
69
  possibly-unused-variable,
70
+ possibly-used-before-assignment,
66
71
  protected-access,
67
72
  raise-missing-from, # Python 2.x does not support raise from
68
73
  redefined-argument-from-local,
@@ -90,6 +95,7 @@ disable=
90
95
  too-many-public-methods,
91
96
  too-many-return-statements,
92
97
  too-many-statements,
98
+ too-many-positional-arguments,
93
99
  try-except-raise,
94
100
  unbalanced-tuple-unpacking,
95
101
  undefined-loop-variable,
@@ -5,8 +5,6 @@
5
5
  from __future__ import annotations
6
6
 
7
7
  import datetime
8
- import functools
9
- import json
10
8
  import re
11
9
  import shlex
12
10
  import typing as t
@@ -326,15 +324,6 @@ class AnsibleDeprecatedCommentChecker(BaseTokenChecker):
326
324
  {'minversion': (2, 6)}),
327
325
  }
328
326
 
329
- options = (
330
- ('min-python-version-db', {
331
- 'default': None,
332
- 'type': 'string',
333
- 'metavar': '<path>',
334
- 'help': 'The path to the DB mapping paths to minimum Python versions.',
335
- }),
336
- )
337
-
338
327
  def process_tokens(self, tokens: list[TokenInfo]) -> None:
339
328
  for token in tokens:
340
329
  if token.type == COMMENT:
@@ -365,15 +354,8 @@ class AnsibleDeprecatedCommentChecker(BaseTokenChecker):
365
354
  )
366
355
  return data
367
356
 
368
- @functools.cached_property
369
- def _min_python_version_db(self) -> dict[str, str]:
370
- """A dictionary of absolute file paths and their minimum required Python version."""
371
- with open(self.linter.config.min_python_version_db) as db_file:
372
- return json.load(db_file)
373
-
374
357
  def _process_python_version(self, token: TokenInfo, data: dict[str, str]) -> None:
375
- current_file = self.linter.current_file
376
- check_version = self._min_python_version_db[current_file]
358
+ check_version = '.'.join(map(str, self.linter.config.py_version))
377
359
 
378
360
  try:
379
361
  if LooseVersion(data['python_version']) < LooseVersion(check_version):
@@ -1,2 +1,3 @@
1
1
  SC1090
2
2
  SC1091
3
+ SC2028