From 1f2817fa2094357a424ad0998021bea16532daee Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Sun, 5 Oct 2025 20:22:50 +0200 Subject: [PATCH] Prepare 5.0.0 (#1123) * Bump version to 5.0.0-a1. * Drop support for ansible-core 2.15 and 2.16. * Remove Python 2 and early Python 3 compatibility. --- LICENSES/MIT.txt | 18 ---- README.md | 3 +- antsibull-nox.toml | 57 +---------- changelogs/fragments/5.0.0.yml | 5 + galaxy.yml | 3 +- meta/runtime.yml | 2 +- plugins/action/docker_container_copy_into.py | 3 +- plugins/connection/docker.py | 9 +- plugins/connection/docker_api.py | 3 +- plugins/connection/nsenter.py | 6 +- plugins/doc_fragments/attributes.py | 3 +- plugins/doc_fragments/compose_v2.py | 3 +- plugins/doc_fragments/docker.py | 4 +- plugins/inventory/docker_containers.py | 4 +- plugins/inventory/docker_machine.py | 3 +- plugins/inventory/docker_swarm.py | 5 +- plugins/module_utils/_api/_import_helper.py | 26 +---- plugins/module_utils/_api/api/client.py | 28 +++--- plugins/module_utils/_api/api/daemon.py | 3 +- plugins/module_utils/_api/auth.py | 11 +-- plugins/module_utils/_api/constants.py | 3 +- plugins/module_utils/_api/context/api.py | 9 +- plugins/module_utils/_api/context/config.py | 3 +- plugins/module_utils/_api/context/context.py | 9 +- .../_api/credentials/constants.py | 3 +- .../module_utils/_api/credentials/errors.py | 3 +- .../module_utils/_api/credentials/store.py | 26 ++--- .../module_utils/_api/credentials/utils.py | 40 ++------ plugins/module_utils/_api/errors.py | 6 +- plugins/module_utils/_api/tls.py | 20 +--- .../_api/transport/basehttpadapter.py | 3 +- .../module_utils/_api/transport/npipeconn.py | 5 +- .../_api/transport/npipesocket.py | 14 +-- .../module_utils/_api/transport/sshconn.py | 10 +- .../module_utils/_api/transport/ssladapter.py | 3 +- .../module_utils/_api/transport/unixconn.py | 14 +-- plugins/module_utils/_api/types/daemon.py | 3 +- plugins/module_utils/_api/utils/build.py | 16 +-- plugins/module_utils/_api/utils/config.py | 3 +- plugins/module_utils/_api/utils/decorators.py | 3 +- plugins/module_utils/_api/utils/fnmatch.py | 3 +- .../module_utils/_api/utils/json_stream.py | 11 +-- plugins/module_utils/_api/utils/ports.py | 3 +- plugins/module_utils/_api/utils/proxy.py | 3 +- plugins/module_utils/_api/utils/socket.py | 13 +-- plugins/module_utils/_api/utils/utils.py | 56 ++++------- plugins/module_utils/_logfmt.py | 3 +- plugins/module_utils/_platform.py | 3 +- plugins/module_utils/_scramble.py | 25 ++--- plugins/module_utils/_six.py | 98 ------------------- plugins/module_utils/common.py | 13 +-- plugins/module_utils/common_api.py | 7 +- plugins/module_utils/common_cli.py | 21 +--- plugins/module_utils/compose_v2.py | 9 +- plugins/module_utils/copy.py | 27 ++--- plugins/module_utils/image_archive.py | 64 ++++-------- plugins/module_utils/module_container/base.py | 12 +-- .../module_container/docker_api.py | 3 +- .../module_utils/module_container/module.py | 3 +- plugins/module_utils/selectors.py | 13 +-- plugins/module_utils/socket_handler.py | 7 +- plugins/module_utils/socket_helper.py | 7 +- plugins/module_utils/swarm.py | 3 +- plugins/module_utils/util.py | 7 +- plugins/module_utils/version.py | 3 +- plugins/modules/current_container_facts.py | 3 +- plugins/modules/docker_compose_v2.py | 6 +- plugins/modules/docker_compose_v2_exec.py | 6 +- plugins/modules/docker_compose_v2_pull.py | 3 +- plugins/modules/docker_compose_v2_run.py | 6 +- plugins/modules/docker_config.py | 3 +- plugins/modules/docker_container.py | 3 +- plugins/modules/docker_container_copy_into.py | 25 +++-- plugins/modules/docker_container_exec.py | 9 +- plugins/modules/docker_container_info.py | 3 +- plugins/modules/docker_context_info.py | 6 +- plugins/modules/docker_host_info.py | 3 +- plugins/modules/docker_image.py | 3 +- plugins/modules/docker_image_build.py | 3 +- plugins/modules/docker_image_export.py | 3 +- plugins/modules/docker_image_info.py | 3 +- plugins/modules/docker_image_load.py | 3 +- plugins/modules/docker_image_pull.py | 3 +- plugins/modules/docker_image_push.py | 3 +- plugins/modules/docker_image_remove.py | 3 +- plugins/modules/docker_image_tag.py | 3 +- plugins/modules/docker_login.py | 3 +- plugins/modules/docker_network.py | 3 +- plugins/modules/docker_network_info.py | 3 +- plugins/modules/docker_node.py | 4 +- plugins/modules/docker_node_info.py | 3 +- plugins/modules/docker_plugin.py | 3 +- plugins/modules/docker_prune.py | 3 +- plugins/modules/docker_secret.py | 3 +- plugins/modules/docker_stack.py | 6 +- plugins/modules/docker_stack_info.py | 4 +- plugins/modules/docker_stack_task_info.py | 4 +- plugins/modules/docker_swarm.py | 3 +- plugins/modules/docker_swarm_info.py | 4 +- plugins/modules/docker_swarm_service.py | 20 ++-- plugins/modules/docker_swarm_service_info.py | 3 +- plugins/modules/docker_volume.py | 8 +- plugins/modules/docker_volume_info.py | 3 +- plugins/plugin_utils/common_api.py | 3 +- plugins/plugin_utils/socket_handler.py | 2 +- plugins/plugin_utils/unsafe.py | 3 +- tests/sanity/ignore-2.15.txt | 10 -- tests/sanity/ignore-2.15.txt.license | 3 - tests/sanity/ignore-2.16.txt | 9 -- tests/sanity/ignore-2.16.txt.license | 3 - tests/sanity/ignore-2.17.txt | 5 - tests/sanity/ignore-2.18.txt | 4 - tests/sanity/ignore-2.19.txt | 4 - tests/sanity/ignore-2.20.txt | 4 - tests/unit/plugins/connection/test_docker.py | 1 - .../module_utils/_api/api/test_client.py | 25 ++--- .../plugins/module_utils/_api/test_auth.py | 4 - .../plugins/module_utils/_api/test_errors.py | 5 - .../_api/transport/test_sshconn.py | 6 -- .../_api/transport/test_ssladapter.py | 4 - .../module_utils/_api/utils/test_build.py | 4 - .../module_utils/_api/utils/test_config.py | 6 -- .../_api/utils/test_decorators.py | 6 -- .../_api/utils/test_json_stream.py | 7 -- .../module_utils/_api/utils/test_ports.py | 4 - .../module_utils/_api/utils/test_proxy.py | 6 -- .../module_utils/_api/utils/test_utils.py | 16 +-- tests/unit/plugins/module_utils/test_copy.py | 3 +- .../module_utils/test_image_archive.py | 10 +- .../unit/plugins/modules/test_docker_image.py | 3 +- .../unit/plugins/plugin_utils/test_unsafe.py | 5 +- .../docker_image_archive_stubbing.py | 7 +- tests/unit/requirements.txt | 4 - 133 files changed, 278 insertions(+), 893 deletions(-) delete mode 100644 LICENSES/MIT.txt create mode 100644 changelogs/fragments/5.0.0.yml delete mode 100644 plugins/module_utils/_six.py delete mode 100644 tests/sanity/ignore-2.15.txt delete mode 100644 tests/sanity/ignore-2.15.txt.license delete mode 100644 tests/sanity/ignore-2.16.txt delete mode 100644 tests/sanity/ignore-2.16.txt.license diff --git a/LICENSES/MIT.txt b/LICENSES/MIT.txt deleted file mode 100644 index 1cc22a5a..00000000 --- a/LICENSES/MIT.txt +++ /dev/null @@ -1,18 +0,0 @@ -Copyright (c) 2010-2024 Benjamin Peterson - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index b7b5b832..a4d35f24 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ For more information about communication, see the [Ansible communication guide]( ## Tested with Ansible -Tested with the current ansible-core 2.15, ansible-core 2.16, ansible-core 2.17, ansible-core 2.18, and ansible-core 2.19 releases, and the current development version of ansible-core. Ansible/ansible-base versions before 2.15.0 are not supported. +Tested with the current ansible-core 2.17, ansible-core 2.18, and ansible-core 2.19 releases, and the current development version of ansible-core. Ansible/ansible-base versions before 2.17.0 are not supported. ## External requirements @@ -160,6 +160,5 @@ This collection is primarily licensed and distributed as a whole under the GNU G See [LICENSES/GPL-3.0-or-later.txt](https://github.com/ansible-collections/community.docker/blob/main/COPYING) for the full text. Parts of the collection are licensed under the [Apache 2.0 license](https://github.com/ansible-collections/community.docker/blob/main/LICENSES/Apache-2.0.txt). This mostly applies to files vendored from the [Docker SDK for Python](https://github.com/docker/docker-py/). -Also `plugins/module_utils/_six.py` is licensed under the [MIT license](https://github.com/ansible-collections/community.dns/blob/main/LICENSES/MIT.txt). All files have a machine readable `SDPX-License-Identifier:` comment denoting its respective license(s) or an equivalent entry in an accompanying `.license` file. Only changelog fragments (which will not be part of a release) are covered by a blanket statement in `REUSE.toml`. This conforms to the [REUSE specification](https://reuse.software/spec/). diff --git a/antsibull-nox.toml b/antsibull-nox.toml index 2aa5cc7f..5e67f64f 100644 --- a/antsibull-nox.toml +++ b/antsibull-nox.toml @@ -8,16 +8,6 @@ "community.internal_test_tools" = "git+https://github.com/ansible-collections/community.internal_test_tools.git,main" "community.library_inventory_filtering_v1" = "git+https://github.com/ansible-collections/community.library_inventory_filtering.git,stable-1" -[collection_sources_per_ansible.'2.15'] -# community.crypto's main branch needs ansible-core >= 2.17 -"community.crypto" = "git+https://github.com/ansible-collections/community.crypto.git,stable-2" -# community.general's main branch needs ansible-core >= 2.16 -"community.general" = "git+https://github.com/ansible-collections/community.general.git,stable-10" - -[collection_sources_per_ansible.'2.16'] -# community.crypto's main branch needs ansible-core >= 2.17 -"community.crypto" = "git+https://github.com/ansible-collections/community.crypto.git,stable-2" - [vcs] vcs = "git" development_branch = "main" @@ -94,45 +84,6 @@ force_docker_sdk_for_python_pypi = { type = "value", value = false, template_val ################################################################################################## -# Ansible-core 2.15: - -[[sessions.ansible_test_integration.groups]] -session_name = "ansible-test-integration-2.15" -description = "Meta session for running all ansible-test-integration-2.15-* sessions." - -[[sessions.ansible_test_integration.groups.sessions]] -ansible_core = "2.15" -target = [ "azp/4/", "azp/5/" ] -docker = [ "fedora37" ] - -[[sessions.ansible_test_integration.groups.sessions]] -ansible_core = "2.15" -target = [ "azp/1/", "azp/2/", "azp/3/", "azp/4/", "azp/5/" ] -remote = [ "rhel/9.1", "rhel/8.7", "rhel/7.9" ] - -# Ansible-core 2.16: - -[[sessions.ansible_test_integration.groups]] -session_name = "ansible-test-integration-2.16" -description = "Meta session for running all ansible-test-integration-2.16-* sessions." - -[[sessions.ansible_test_integration.groups.sessions]] -ansible_core = "2.16" -target = [ "azp/4/", "azp/5/" ] -docker = [ "fedora38", "opensuse15", "alpine3" ] - -[[sessions.ansible_test_integration.groups.sessions]] -ansible_core = "2.16" -target = [ "azp/4/", "azp/5/" ] -docker = [ "centos7" ] -# "centos7" does not work in GHA: -tags = [ "no-gha" ] - -[[sessions.ansible_test_integration.groups.sessions]] -ansible_core = "2.16" -target = [ "azp/1/", "azp/2/", "azp/3/", "azp/4/", "azp/5/" ] -remote = [ "rhel/8.8", "rhel/7.9" ] - # Ansible-core 2.17: [[sessions.ansible_test_integration.groups]] @@ -254,12 +205,14 @@ runtime_container_options = [ ] [[sessions.ee_check.execution_environments]] -name = "2.15-rocky-9" -description = "ansible-core 2.15 @ Rocky Linux 9" +name = "2.17-rocky-9" +description = "ansible-core 2.17 @ Rocky Linux 9" test_playbooks = ["tests/ee/all.yml"] config.images.base_image.name = "quay.io/rockylinux/rockylinux:9" -config.dependencies.ansible_core.package_pip = "https://github.com/ansible/ansible/archive/stable-2.15.tar.gz" +config.dependencies.ansible_core.package_pip = "https://github.com/ansible/ansible/archive/stable-2.17.tar.gz" config.dependencies.ansible_runner.package_pip = "ansible-runner" +config.dependencies.python_interpreter.package_system = "python3.11 python3.11-pip python3.11-wheel python3.11-cryptography" +config.dependencies.python_interpreter.python_path = "/usr/bin/python3.11" runtime_environment = {"ANSIBLE_PRIVATE_ROLE_VARS" = "true"} runtime_container_options = [ # Mount Docker socket into the container so we can talk to Docker outside the container diff --git a/changelogs/fragments/5.0.0.yml b/changelogs/fragments/5.0.0.yml new file mode 100644 index 00000000..243070ce --- /dev/null +++ b/changelogs/fragments/5.0.0.yml @@ -0,0 +1,5 @@ +removed_features: + - The collection no longer supports ansible-core 2.15 and 2.16. + You need ansible-core 2.17.0 or newer to use community.docker 5.x.y (https://github.com/ansible-collections/community.docker/pull/1123). + - The collection no longer supports Python 3.6 and before. + Note that this coincides with the Python requirements of ansible-core 2.17+ (https://github.com/ansible-collections/community.docker/pull/1123). diff --git a/galaxy.yml b/galaxy.yml index 8806b99a..aba5b06c 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -7,7 +7,7 @@ namespace: community name: docker -version: 4.8.1 +version: 5.0.0-a1 readme: README.md authors: - Ansible Docker Working Group @@ -15,7 +15,6 @@ description: Modules and plugins for working with Docker license: - GPL-3.0-or-later - Apache-2.0 - - MIT # license_file: COPYING tags: - docker diff --git a/meta/runtime.yml b/meta/runtime.yml index e228ab55..2ad0ed18 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -3,7 +3,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -requires_ansible: '>=2.15.0' +requires_ansible: '>=2.17.0' action_groups: docker: - docker_compose_v2 diff --git a/plugins/action/docker_container_copy_into.py b/plugins/action/docker_container_copy_into.py index fed0af00..ffdcfe9f 100644 --- a/plugins/action/docker_container_copy_into.py +++ b/plugins/action/docker_container_copy_into.py @@ -2,8 +2,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations import base64 diff --git a/plugins/connection/docker.py b/plugins/connection/docker.py index ad6e2340..b27b08b8 100644 --- a/plugins/connection/docker.py +++ b/plugins/connection/docker.py @@ -7,8 +7,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" author: @@ -115,9 +114,10 @@ options: import fcntl import os import os.path +import selectors import subprocess import re -from shlex import quote as shlex_quote +from shlex import quote from ansible.errors import AnsibleError, AnsibleFileNotFound, AnsibleConnectionFailure from ansible.module_utils.common.process import get_bin_path @@ -125,7 +125,6 @@ from ansible.module_utils.common.text.converters import to_bytes, to_native, to_ from ansible.plugins.connection import ConnectionBase, BUFSIZE from ansible.utils.display import Display -from ansible_collections.community.docker.plugins.module_utils.selectors import selectors from ansible_collections.community.docker.plugins.module_utils.version import LooseVersion display = Display() @@ -433,7 +432,7 @@ class Connection(ConnectionBase): raise AnsibleFileNotFound( "file or module does not exist: %s" % to_native(in_path)) - out_path = shlex_quote(out_path) + out_path = quote(out_path) # Older docker does not have native support for copying files into # running containers, so we use docker exec to implement this # Although docker version 1.8 and later provide support, the diff --git a/plugins/connection/docker_api.py b/plugins/connection/docker_api.py index eb21a293..248bac97 100644 --- a/plugins/connection/docker_api.py +++ b/plugins/connection/docker_api.py @@ -2,8 +2,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" author: diff --git a/plugins/connection/nsenter.py b/plugins/connection/nsenter.py index d9a58a9c..2a858104 100644 --- a/plugins/connection/nsenter.py +++ b/plugins/connection/nsenter.py @@ -5,8 +5,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" name: nsenter @@ -42,6 +41,7 @@ notes: import os import pty +import selectors import subprocess import fcntl @@ -52,8 +52,6 @@ from ansible.plugins.connection import ConnectionBase from ansible.utils.display import Display from ansible.utils.path import unfrackpath -from ansible_collections.community.docker.plugins.module_utils.selectors import selectors - display = Display() diff --git a/plugins/doc_fragments/attributes.py b/plugins/doc_fragments/attributes.py index 02faa71e..614d5a26 100644 --- a/plugins/doc_fragments/attributes.py +++ b/plugins/doc_fragments/attributes.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations class ModuleDocFragment(object): diff --git a/plugins/doc_fragments/compose_v2.py b/plugins/doc_fragments/compose_v2.py index 5eae0321..6aeae8d2 100644 --- a/plugins/doc_fragments/compose_v2.py +++ b/plugins/doc_fragments/compose_v2.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations class ModuleDocFragment(object): diff --git a/plugins/doc_fragments/docker.py b/plugins/doc_fragments/docker.py index 2278cb03..59fd084a 100644 --- a/plugins/doc_fragments/docker.py +++ b/plugins/doc_fragments/docker.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations class ModuleDocFragment(object): @@ -303,7 +302,6 @@ requirements: - pywin32 (when using named pipes on Windows 32) - paramiko (when using SSH with O(use_ssh_client=false)) - pyOpenSSL (when using TLS) - - backports.ssl_match_hostname (when using TLS on Python 2) ''' # Docker doc fragment when using the Docker CLI diff --git a/plugins/inventory/docker_containers.py b/plugins/inventory/docker_containers.py index 37ba84db..d8b29c14 100644 --- a/plugins/inventory/docker_containers.py +++ b/plugins/inventory/docker_containers.py @@ -7,9 +7,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) - -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/inventory/docker_machine.py b/plugins/inventory/docker_machine.py index 2415d96c..e284c505 100644 --- a/plugins/inventory/docker_machine.py +++ b/plugins/inventory/docker_machine.py @@ -3,8 +3,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" name: docker_machine diff --git a/plugins/inventory/docker_swarm.py b/plugins/inventory/docker_swarm.py index 6f223e07..9fa8ed12 100644 --- a/plugins/inventory/docker_swarm.py +++ b/plugins/inventory/docker_swarm.py @@ -4,9 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) - -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" name: docker_swarm @@ -14,7 +12,6 @@ author: - Stefan Heitmüller (@morph027) short_description: Ansible dynamic inventory plugin for Docker swarm nodes requirements: - - python >= 2.7 - L(Docker SDK for Python,https://docker-py.readthedocs.io/en/stable/) >= 1.10.0 extends_documentation_fragment: - ansible.builtin.constructed diff --git a/plugins/module_utils/_api/_import_helper.py b/plugins/module_utils/_api/_import_helper.py index 29151d80..f464f776 100644 --- a/plugins/module_utils/_api/_import_helper.py +++ b/plugins/module_utils/_api/_import_helper.py @@ -7,17 +7,13 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import traceback -from ansible_collections.community.docker.plugins.module_utils._six import PY2 - REQUESTS_IMPORT_ERROR = None URLLIB3_IMPORT_ERROR = None -BACKPORTS_SSL_MATCH_HOSTNAME_IMPORT_ERROR = None try: @@ -41,11 +37,11 @@ except ImportError: try: - from requests.packages import urllib3 + from requests.packages import urllib3 # pylint: disable=unused-import from requests.packages.urllib3 import connection as urllib3_connection # pylint: disable=unused-import except ImportError: try: - import urllib3 + import urllib3 # pylint: disable=unused-import from urllib3 import connection as urllib3_connection # pylint: disable=unused-import except ImportError: URLLIB3_IMPORT_ERROR = traceback.format_exc() @@ -76,16 +72,6 @@ except ImportError: urllib3_connection = FakeURLLIB3Connection() -# Monkey-patching match_hostname with a version that supports -# IP-address checking. Not necessary for Python 3.5 and above -if PY2: - try: - from backports.ssl_match_hostname import match_hostname - urllib3.connection.match_hostname = match_hostname - except ImportError: - BACKPORTS_SSL_MATCH_HOSTNAME_IMPORT_ERROR = traceback.format_exc() - - def fail_on_missing_imports(): if REQUESTS_IMPORT_ERROR is not None: from .errors import MissingRequirementException @@ -99,9 +85,3 @@ def fail_on_missing_imports(): raise MissingRequirementException( 'You have to install urllib3', 'urllib3', URLLIB3_IMPORT_ERROR) - if BACKPORTS_SSL_MATCH_HOSTNAME_IMPORT_ERROR is not None: - from .errors import MissingRequirementException - - raise MissingRequirementException( - 'You have to install backports.ssl-match-hostname', - 'backports.ssl-match-hostname', BACKPORTS_SSL_MATCH_HOSTNAME_IMPORT_ERROR) diff --git a/plugins/module_utils/_api/api/client.py b/plugins/module_utils/_api/api/client.py index ea5baa2c..b539671f 100644 --- a/plugins/module_utils/_api/api/client.py +++ b/plugins/module_utils/_api/api/client.py @@ -7,15 +7,13 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import json import logging import struct from functools import partial - -from ansible_collections.community.docker.plugins.module_utils._six import PY3, binary_type, iteritems, string_types, raise_from, quote +from urllib.parse import quote from .. import auth from .._import_helper import fail_on_missing_imports @@ -183,11 +181,11 @@ class APIClient( self.base_url = base_url # version detection needs to be after unix adapter mounting - if version is None or (isinstance(version, string_types) and version.lower() == 'auto'): + if version is None or (isinstance(version, str) and version.lower() == 'auto'): self._version = self._retrieve_server_version() else: self._version = version - if not isinstance(self._version, string_types): + if not isinstance(self._version, str): raise DockerException( 'Version parameter must be a string or None. Found {0}'.format( type(version).__name__ @@ -247,7 +245,7 @@ class APIClient( def _url(self, pathfmt, *args, **kwargs): for arg in args: - if not isinstance(arg, string_types): + if not isinstance(arg, str): raise ValueError( 'Expected a string but found {0} ({1}) ' 'instead'.format(arg, type(arg)) @@ -268,7 +266,7 @@ class APIClient( try: response.raise_for_status() except _HTTPError as e: - raise_from(create_api_error_from_http_exception(e), e) + create_api_error_from_http_exception(e) def _result(self, response, json=False, binary=False): if json and binary: @@ -286,7 +284,7 @@ class APIClient( # so we do this disgusting thing here. data2 = {} if data is not None and isinstance(data, dict): - for k, v in iteritems(data): + for k, v in data.items(): if v is not None: data2[k] = v elif data is not None: @@ -310,12 +308,10 @@ class APIClient( sock = response.raw._fp.fp.raw.sock elif self.base_url.startswith('http+docker://ssh'): sock = response.raw._fp.fp.channel - elif PY3: + else: sock = response.raw._fp.fp.raw if self.base_url.startswith("https://"): sock = sock._sock - else: - sock = response.raw._fp.fp._sock try: # Keep a reference to the response to stop it being garbage # collected. If the response is garbage collected, it will @@ -333,8 +329,7 @@ class APIClient( if response.raw._fp.chunked: if decode: - for chunk in json_stream.json_stream(self._stream_helper(response, False)): - yield chunk + yield from json_stream.json_stream(self._stream_helper(response, False)) else: reader = response.raw while not reader.closed: @@ -396,8 +391,7 @@ class APIClient( socket = self._get_raw_response_socket(response) self._disable_socket_timeout(socket) - for out in response.iter_content(chunk_size, decode): - yield out + yield from response.iter_content(chunk_size, decode) def _read_from_socket(self, response, stream, tty=True, demux=False): """Consume all data from the socket, close the response and return the @@ -468,7 +462,7 @@ class APIClient( self._result(res, binary=True) self._raise_for_status(res) - sep = binary_type() + sep = b'' if stream: return self._multiplexed_response_stream_helper(res) else: diff --git a/plugins/module_utils/_api/api/daemon.py b/plugins/module_utils/_api/api/daemon.py index 55164c0b..f69af9cc 100644 --- a/plugins/module_utils/_api/api/daemon.py +++ b/plugins/module_utils/_api/api/daemon.py @@ -7,8 +7,7 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import os diff --git a/plugins/module_utils/_api/auth.py b/plugins/module_utils/_api/auth.py index e80eb660..e23825fd 100644 --- a/plugins/module_utils/_api/auth.py +++ b/plugins/module_utils/_api/auth.py @@ -7,15 +7,12 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import base64 import json import logging -from ansible_collections.community.docker.plugins.module_utils._six import iteritems, string_types - from . import errors from .credentials.store import Store from .credentials.errors import StoreError, CredentialsNotFound @@ -111,7 +108,7 @@ class AuthConfig(dict): """ conf = {} - for registry, entry in iteritems(entries): + for registry, entry in entries.items(): if not isinstance(entry, dict): log.debug('Config entry for key %s is not auth config', registry) # We sometimes fall back to parsing the whole config as if it @@ -242,7 +239,7 @@ class AuthConfig(dict): log.debug("Found %s", repr(registry)) return self.auths[registry] - for key, conf in iteritems(self.auths): + for key, conf in self.auths.items(): if resolve_index_name(key) == registry: log.debug("Found %s", repr(key)) return conf @@ -326,7 +323,7 @@ def convert_to_hostname(url): def decode_auth(auth): - if isinstance(auth, string_types): + if isinstance(auth, str): auth = auth.encode('ascii') s = base64.b64decode(auth) login, pwd = s.split(b':', 1) diff --git a/plugins/module_utils/_api/constants.py b/plugins/module_utils/_api/constants.py index f1340cbf..b0e48501 100644 --- a/plugins/module_utils/_api/constants.py +++ b/plugins/module_utils/_api/constants.py @@ -7,8 +7,7 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import sys diff --git a/plugins/module_utils/_api/context/api.py b/plugins/module_utils/_api/context/api.py index 9bf82f96..879a8613 100644 --- a/plugins/module_utils/_api/context/api.py +++ b/plugins/module_utils/_api/context/api.py @@ -7,14 +7,11 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import json import os -from ansible_collections.community.docker.plugins.module_utils._six import raise_from - from .. import errors from .config import ( @@ -148,9 +145,9 @@ class ContextAPI(object): raise ValueError('"default" is a reserved context name') names.append(name) except Exception as e: - raise_from(errors.ContextException( + raise errors.ContextException( "Failed to load metafile {filepath}: {e}".format(filepath=filepath, e=e), - ), e) + ) from e contexts = [cls.get_default_context()] for name in names: diff --git a/plugins/module_utils/_api/context/config.py b/plugins/module_utils/_api/context/config.py index 77b2e01f..3ac4e833 100644 --- a/plugins/module_utils/_api/context/config.py +++ b/plugins/module_utils/_api/context/config.py @@ -7,8 +7,7 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import hashlib import json diff --git a/plugins/module_utils/_api/context/context.py b/plugins/module_utils/_api/context/context.py index 9060b38c..dde4fc56 100644 --- a/plugins/module_utils/_api/context/context.py +++ b/plugins/module_utils/_api/context/context.py @@ -7,15 +7,12 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import json import os from shutil import copyfile, rmtree -from ansible_collections.community.docker.plugins.module_utils._six import raise_from - from ..errors import ContextException from ..tls import TLSConfig @@ -120,9 +117,9 @@ class Context(object): metadata = json.load(f) except (OSError, KeyError, ValueError) as e: # unknown format - raise_from(Exception( + raise Exception( "Detected corrupted meta file for context {name} : {e}".format(name=name, e=e) - ), e) + ) from e # for docker endpoints, set defaults for # Host and SkipTLSVerify fields diff --git a/plugins/module_utils/_api/credentials/constants.py b/plugins/module_utils/_api/credentials/constants.py index c52bc564..710d7573 100644 --- a/plugins/module_utils/_api/credentials/constants.py +++ b/plugins/module_utils/_api/credentials/constants.py @@ -7,8 +7,7 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations PROGRAM_PREFIX = 'docker-credential-' DEFAULT_LINUX_STORE = 'secretservice' diff --git a/plugins/module_utils/_api/credentials/errors.py b/plugins/module_utils/_api/credentials/errors.py index 0047e8e4..905b4121 100644 --- a/plugins/module_utils/_api/credentials/errors.py +++ b/plugins/module_utils/_api/credentials/errors.py @@ -7,8 +7,7 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations class StoreError(RuntimeError): diff --git a/plugins/module_utils/_api/credentials/store.py b/plugins/module_utils/_api/credentials/store.py index 57398b6b..1cbc112e 100644 --- a/plugins/module_utils/_api/credentials/store.py +++ b/plugins/module_utils/_api/credentials/store.py @@ -7,15 +7,12 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import errno import json import subprocess -from ansible_collections.community.docker.plugins.module_utils._six import PY3, binary_type - from . import constants from . import errors from .utils import create_environment_dict @@ -42,7 +39,7 @@ class Store(object): """ Retrieve credentials for `server`. If no credentials are found, a `StoreError` will be raised. """ - if not isinstance(server, binary_type): + if not isinstance(server, bytes): server = server.encode('utf-8') data = self._execute('get', server) result = json.loads(data.decode('utf-8')) @@ -73,7 +70,7 @@ class Store(object): """ Erase credentials for `server`. Raises a `StoreError` if an error occurs. """ - if not isinstance(server, binary_type): + if not isinstance(server, bytes): server = server.encode('utf-8') self._execute('erase', server) @@ -87,20 +84,9 @@ class Store(object): output = None env = create_environment_dict(self.environment) try: - if PY3: - output = subprocess.check_output( - [self.exe, subcmd], input=data_input, env=env, - ) - else: - process = subprocess.Popen( - [self.exe, subcmd], stdin=subprocess.PIPE, - stdout=subprocess.PIPE, env=env, - ) - output, dummy = process.communicate(data_input) - if process.returncode != 0: - raise subprocess.CalledProcessError( - returncode=process.returncode, cmd='', output=output - ) + output = subprocess.check_output( + [self.exe, subcmd], input=data_input, env=env, + ) except subprocess.CalledProcessError as e: raise errors.process_store_error(e, self.program) except OSError as e: diff --git a/plugins/module_utils/_api/credentials/utils.py b/plugins/module_utils/_api/credentials/utils.py index 6dd62cd9..f8810381 100644 --- a/plugins/module_utils/_api/credentials/utils.py +++ b/plugins/module_utils/_api/credentials/utils.py @@ -7,18 +7,11 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import os -import sys -from ansible_collections.community.docker.plugins.module_utils._six import PY2 - -if PY2: - from distutils.spawn import find_executable as which -else: - from shutil import which +from shutil import which def find_executable(executable, path=None): @@ -26,31 +19,10 @@ def find_executable(executable, path=None): As distutils.spawn.find_executable, but on Windows, look up every extension declared in PATHEXT instead of just `.exe` """ - if not PY2: - # shutil.which() already uses PATHEXT on Windows, so on - # Python 3 we can simply use shutil.which() in all cases. - # (https://github.com/docker/docker-py/commit/42789818bed5d86b487a030e2e60b02bf0cfa284) - return which(executable, path=path) - - if sys.platform != 'win32': - return which(executable, path) - - if path is None: - path = os.environ['PATH'] - - paths = path.split(os.pathsep) - extensions = os.environ.get('PATHEXT', '.exe').split(os.pathsep) - base, ext = os.path.splitext(executable) - - if not os.path.isfile(executable): - for p in paths: - for ext in extensions: - f = os.path.join(p, base + ext) - if os.path.isfile(f): - return f - return None - else: - return executable + # shutil.which() already uses PATHEXT on Windows, so on + # Python 3 we can simply use shutil.which() in all cases. + # (https://github.com/docker/docker-py/commit/42789818bed5d86b487a030e2e60b02bf0cfa284) + return which(executable, path=path) def create_environment_dict(overrides): diff --git a/plugins/module_utils/_api/errors.py b/plugins/module_utils/_api/errors.py index 4e86a276..a81bef3d 100644 --- a/plugins/module_utils/_api/errors.py +++ b/plugins/module_utils/_api/errors.py @@ -7,13 +7,11 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations from ._import_helper import HTTPError as _HTTPError from ansible.module_utils.common.text.converters import to_native -from ansible_collections.community.docker.plugins.module_utils._six import raise_from class DockerException(Exception): @@ -43,7 +41,7 @@ def create_api_error_from_http_exception(e): cls = ImageNotFound else: cls = NotFound - raise_from(cls(e, response=response, explanation=explanation), e) + raise cls(e, response=response, explanation=explanation) from e class APIError(_HTTPError, DockerException): diff --git a/plugins/module_utils/_api/tls.py b/plugins/module_utils/_api/tls.py index b1e284a5..b8c96352 100644 --- a/plugins/module_utils/_api/tls.py +++ b/plugins/module_utils/_api/tls.py @@ -7,12 +7,10 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import os import ssl -import sys from . import errors from .transport.ssladapter import SSLHTTPAdapter @@ -51,22 +49,6 @@ class TLSConfig(object): # If the user provides an SSL version, we should use their preference if ssl_version: self.ssl_version = ssl_version - elif (sys.version_info.major, sys.version_info.minor) < (3, 6): - # If the user provides no ssl version, we should default to - # TLSv1_2. This option is the most secure, and will work for the - # majority of users with reasonably up-to-date software. However, - # before doing so, detect openssl version to ensure we can support - # it. - if ssl.OPENSSL_VERSION_INFO[:3] >= (1, 0, 1) and hasattr( - ssl, 'PROTOCOL_TLSv1_2'): - # If the OpenSSL version is high enough to support TLSv1_2, - # then we should use it. - self.ssl_version = getattr(ssl, 'PROTOCOL_TLSv1_2') - else: - # Otherwise, TLS v1.0 seems to be the safest default; - # SSLv23 fails in mysterious ways: - # https://github.com/docker/docker-py/issues/963 - self.ssl_version = ssl.PROTOCOL_TLSv1 else: self.ssl_version = ssl.PROTOCOL_TLS_CLIENT diff --git a/plugins/module_utils/_api/transport/basehttpadapter.py b/plugins/module_utils/_api/transport/basehttpadapter.py index 14062a0b..bc27e397 100644 --- a/plugins/module_utils/_api/transport/basehttpadapter.py +++ b/plugins/module_utils/_api/transport/basehttpadapter.py @@ -7,8 +7,7 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations from .._import_helper import HTTPAdapter as _HTTPAdapter diff --git a/plugins/module_utils/_api/transport/npipeconn.py b/plugins/module_utils/_api/transport/npipeconn.py index 089b067f..8b919594 100644 --- a/plugins/module_utils/_api/transport/npipeconn.py +++ b/plugins/module_utils/_api/transport/npipeconn.py @@ -7,10 +7,9 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations -from ansible_collections.community.docker.plugins.module_utils._six import Empty +from queue import Empty from .. import constants from .._import_helper import HTTPAdapter, urllib3, urllib3_connection diff --git a/plugins/module_utils/_api/transport/npipesocket.py b/plugins/module_utils/_api/transport/npipesocket.py index 3fb1557b..7cf86df1 100644 --- a/plugins/module_utils/_api/transport/npipesocket.py +++ b/plugins/module_utils/_api/transport/npipesocket.py @@ -7,16 +7,13 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import functools import io import time import traceback -from ansible_collections.community.docker.plugins.module_utils._six import PY2 - PYWIN32_IMPORT_ERROR = None try: import win32file @@ -152,9 +149,6 @@ class NpipeSocket(object): @check_closed def recv_into(self, buf, nbytes=0): - if PY2: - return self._recv_into_py2(buf, nbytes) - readbuf = buf if not isinstance(buf, memoryview): readbuf = memoryview(buf) @@ -176,12 +170,6 @@ class NpipeSocket(object): finally: win32api.CloseHandle(event) - def _recv_into_py2(self, buf, nbytes): - err, data = win32file.ReadFile(self._handle, nbytes or len(buf)) - n = len(data) - buf[:n] = data - return n - @check_closed def send(self, string, flags=0): event = win32event.CreateEvent(None, True, True, None) diff --git a/plugins/module_utils/_api/transport/sshconn.py b/plugins/module_utils/_api/transport/sshconn.py index 1edc6e88..92ca9d3d 100644 --- a/plugins/module_utils/_api/transport/sshconn.py +++ b/plugins/module_utils/_api/transport/sshconn.py @@ -7,8 +7,7 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import logging import os @@ -16,8 +15,8 @@ import signal import socket import subprocess import traceback - -from ansible_collections.community.docker.plugins.module_utils._six import PY3, Empty, urlparse +from queue import Empty +from urllib.parse import urlparse from .basehttpadapter import BaseHTTPAdapter from .. import constants @@ -100,8 +99,7 @@ class SSHSocket(socket.socket): def makefile(self, mode): if not self.proc: self.connect() - if PY3: - self.proc.stdout.channel = self + self.proc.stdout.channel = self return self.proc.stdout diff --git a/plugins/module_utils/_api/transport/ssladapter.py b/plugins/module_utils/_api/transport/ssladapter.py index 7f5906e6..5876be36 100644 --- a/plugins/module_utils/_api/transport/ssladapter.py +++ b/plugins/module_utils/_api/transport/ssladapter.py @@ -7,8 +7,7 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations """ Resolves OpenSSL issues in some servers: https://lukasa.co.uk/2013/01/Choosing_SSL_Version_In_Requests/ diff --git a/plugins/module_utils/_api/transport/unixconn.py b/plugins/module_utils/_api/transport/unixconn.py index ffbe0b05..2a380a2a 100644 --- a/plugins/module_utils/_api/transport/unixconn.py +++ b/plugins/module_utils/_api/transport/unixconn.py @@ -7,13 +7,10 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import socket -from ansible_collections.community.docker.plugins.module_utils._six import PY2 - from .basehttpadapter import BaseHTTPAdapter from .. import constants @@ -46,12 +43,9 @@ class UnixHTTPConnection(urllib3_connection.HTTPConnection, object): self.disable_buffering = True def response_class(self, sock, *args, **kwargs): - if PY2: - # FIXME: We may need to disable buffering on Py3 as well, - # but there's no clear way to do it at the moment. See: - # https://github.com/docker/docker-py/issues/1799 - kwargs['buffering'] = not self.disable_buffering - + # FIXME: We may need to disable buffering on Py3, + # but there's no clear way to do it at the moment. See: + # https://github.com/docker/docker-py/issues/1799 return super(UnixHTTPConnection, self).response_class(sock, *args, **kwargs) diff --git a/plugins/module_utils/_api/types/daemon.py b/plugins/module_utils/_api/types/daemon.py index 47decd44..ec8c44a0 100644 --- a/plugins/module_utils/_api/types/daemon.py +++ b/plugins/module_utils/_api/types/daemon.py @@ -7,8 +7,7 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import socket diff --git a/plugins/module_utils/_api/utils/build.py b/plugins/module_utils/_api/utils/build.py index 1ae2e965..bec03f86 100644 --- a/plugins/module_utils/_api/utils/build.py +++ b/plugins/module_utils/_api/utils/build.py @@ -7,8 +7,7 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import io import os @@ -17,8 +16,6 @@ import re import tarfile import tempfile -from ansible_collections.community.docker.plugins.module_utils._six import PY3 - from . import fnmatch from ..constants import IS_WINDOWS_PLATFORM, WINDOWS_LONGPATH_PREFIX @@ -131,13 +128,7 @@ def mkbuildcontext(dockerfile): f = tempfile.NamedTemporaryFile() t = tarfile.open(mode='w', fileobj=f) if isinstance(dockerfile, io.StringIO): - dfinfo = tarfile.TarInfo('Dockerfile') - if PY3: - raise TypeError('Please use io.BytesIO to create in-memory ' - 'Dockerfiles with Python 3') - else: - dfinfo.size = len(dockerfile.getvalue()) - dockerfile.seek(0) + raise TypeError('Please use io.BytesIO to create in-memory Dockerfiles') elif isinstance(dockerfile, io.BytesIO): dfinfo = tarfile.TarInfo('Dockerfile') dfinfo.size = len(dockerfile.getvalue()) @@ -225,8 +216,7 @@ class PatternMatcher(object): break if skip: continue - for sub in rec_walk(cur): - yield sub + yield from rec_walk(cur) return rec_walk(root) diff --git a/plugins/module_utils/_api/utils/config.py b/plugins/module_utils/_api/utils/config.py index 44ac03cd..e4ecb55b 100644 --- a/plugins/module_utils/_api/utils/config.py +++ b/plugins/module_utils/_api/utils/config.py @@ -7,8 +7,7 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import json import logging diff --git a/plugins/module_utils/_api/utils/decorators.py b/plugins/module_utils/_api/utils/decorators.py index ec2d258a..59abd483 100644 --- a/plugins/module_utils/_api/utils/decorators.py +++ b/plugins/module_utils/_api/utils/decorators.py @@ -7,8 +7,7 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import functools diff --git a/plugins/module_utils/_api/utils/fnmatch.py b/plugins/module_utils/_api/utils/fnmatch.py index 30883250..9181d62c 100644 --- a/plugins/module_utils/_api/utils/fnmatch.py +++ b/plugins/module_utils/_api/utils/fnmatch.py @@ -7,8 +7,7 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations """Filename matching with shell patterns. diff --git a/plugins/module_utils/_api/utils/json_stream.py b/plugins/module_utils/_api/utils/json_stream.py index da9a22a2..e2bd8e92 100644 --- a/plugins/module_utils/_api/utils/json_stream.py +++ b/plugins/module_utils/_api/utils/json_stream.py @@ -7,14 +7,11 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import json import json.decoder -from ansible_collections.community.docker.plugins.module_utils._six import text_type - from ..errors import StreamParseError @@ -29,7 +26,7 @@ def stream_as_text(stream): instead of byte streams. """ for data in stream: - if not isinstance(data, text_type): + if not isinstance(data, str): data = data.decode('utf-8', 'replace') yield data @@ -56,7 +53,7 @@ def json_stream(stream): def line_splitter(buffer, separator=u'\n'): - index = buffer.find(text_type(separator)) + index = buffer.find(str(separator)) if index == -1: return None return buffer[:index + 1], buffer[index + 1:] @@ -70,7 +67,7 @@ def split_buffer(stream, splitter=None, decoder=lambda a: a): of the input. """ splitter = splitter or line_splitter - buffered = text_type('') + buffered = '' for data in stream_as_text(stream): buffered += data diff --git a/plugins/module_utils/_api/utils/ports.py b/plugins/module_utils/_api/utils/ports.py index 194aaa7a..0fb85eed 100644 --- a/plugins/module_utils/_api/utils/ports.py +++ b/plugins/module_utils/_api/utils/ports.py @@ -7,8 +7,7 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import re diff --git a/plugins/module_utils/_api/utils/proxy.py b/plugins/module_utils/_api/utils/proxy.py index ed20ff53..9181ae18 100644 --- a/plugins/module_utils/_api/utils/proxy.py +++ b/plugins/module_utils/_api/utils/proxy.py @@ -7,8 +7,7 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations from .utils import format_environment diff --git a/plugins/module_utils/_api/utils/socket.py b/plugins/module_utils/_api/utils/socket.py index 754447e0..963ed98c 100644 --- a/plugins/module_utils/_api/utils/socket.py +++ b/plugins/module_utils/_api/utils/socket.py @@ -7,8 +7,7 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import errno import os @@ -16,8 +15,6 @@ import select import socket as pysocket import struct -from ansible_collections.community.docker.plugins.module_utils._six import PY3, binary_type - from ..transport.npipesocket import NpipeSocket @@ -41,7 +38,7 @@ def read(socket, n=4096): recoverable_errors = (errno.EINTR, errno.EDEADLK, errno.EWOULDBLOCK) - if PY3 and not isinstance(socket, NpipeSocket): + if not isinstance(socket, NpipeSocket): if not hasattr(select, "poll"): # Limited to 1024 select.select([socket], [], []) @@ -53,7 +50,7 @@ def read(socket, n=4096): try: if hasattr(socket, 'recv'): return socket.recv(n) - if PY3 and isinstance(socket, getattr(pysocket, 'SocketIO')): + if isinstance(socket, getattr(pysocket, 'SocketIO')): return socket.read(n) return os.read(socket.fileno(), n) except EnvironmentError as e: @@ -75,7 +72,7 @@ def read_exactly(socket, n): Reads exactly n bytes from socket Raises SocketError if there is not enough data """ - data = binary_type() + data = b'' while len(data) < n: next_data = read(socket, n - len(data)) if not next_data: @@ -163,7 +160,7 @@ def consume_socket_output(frames, demux=False): if demux is False: # If the streams are multiplexed, the generator returns strings, that # we just need to concatenate. - return binary_type().join(frames) + return b''.join(frames) # If the streams are demultiplexed, the generator yields tuples # (stdout, stderr) diff --git a/plugins/module_utils/_api/utils/utils.py b/plugins/module_utils/_api/utils/utils.py index 1d0781a1..0d7db9f1 100644 --- a/plugins/module_utils/_api/utils/utils.py +++ b/plugins/module_utils/_api/utils/utils.py @@ -7,8 +7,7 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import base64 import collections @@ -19,8 +18,6 @@ import shlex import string from ansible_collections.community.docker.plugins.module_utils.version import StrictVersion -from ansible_collections.community.docker.plugins.module_utils._six import PY2, PY3, binary_type, integer_types, iteritems, string_types, text_type - from .. import errors from ..constants import DEFAULT_HTTP_HOST from ..constants import DEFAULT_UNIX_SOCKET @@ -28,10 +25,7 @@ from ..constants import DEFAULT_NPIPE from ..constants import BYTE_UNITS from ..tls import TLSConfig -if PY2: - from urlparse import urlparse, urlunparse -else: - from urllib.parse import urlparse, urlunparse +from urllib.parse import urlparse, urlunparse URLComponents = collections.namedtuple( @@ -55,9 +49,7 @@ def create_ipam_config(*args, **kwargs): def decode_json_header(header): - data = base64.b64decode(header) - if PY3: - data = data.decode('utf-8') + data = base64.b64decode(header).decode('utf-8') return json.loads(data) @@ -97,7 +89,7 @@ def _convert_port_binding(binding): if len(binding) == 2: result['HostPort'] = binding[1] result['HostIp'] = binding[0] - elif isinstance(binding[0], string_types): + elif isinstance(binding[0], str): result['HostIp'] = binding[0] else: result['HostPort'] = binding[0] @@ -121,7 +113,7 @@ def _convert_port_binding(binding): def convert_port_bindings(port_bindings): result = {} - for k, v in iteritems(port_bindings): + for k, v in port_bindings.items(): key = str(k) if '/' not in key: key += '/tcp' @@ -138,7 +130,7 @@ def convert_volume_binds(binds): result = [] for k, v in binds.items(): - if isinstance(k, binary_type): + if isinstance(k, bytes): k = k.decode('utf-8') if isinstance(v, dict): @@ -149,7 +141,7 @@ def convert_volume_binds(binds): ) bind = v['bind'] - if isinstance(bind, binary_type): + if isinstance(bind, bytes): bind = bind.decode('utf-8') if 'ro' in v: @@ -175,15 +167,11 @@ def convert_volume_binds(binds): else: mode = v['propagation'] - result.append( - text_type('{0}:{1}:{2}').format(k, bind, mode) - ) + result.append('{0}:{1}:{2}'.format(k, bind, mode)) else: - if isinstance(v, binary_type): + if isinstance(v, bytes): v = v.decode('utf-8') - result.append( - text_type('{0}:{1}:rw').format(k, v) - ) + result.append('{0}:{1}:rw'.format(k, v)) return result @@ -199,7 +187,7 @@ def convert_tmpfs_mounts(tmpfs): result = {} for mount in tmpfs: - if isinstance(mount, string_types): + if isinstance(mount, str): if ":" in mount: name, options = mount.split(":", 1) else: @@ -224,7 +212,7 @@ def convert_service_networks(networks): result = [] for n in networks: - if isinstance(n, string_types): + if isinstance(n, str): n = {'Target': n} result.append(n) return result @@ -333,7 +321,7 @@ def parse_devices(devices): if isinstance(device, dict): device_list.append(device) continue - if not isinstance(device, string_types): + if not isinstance(device, str): raise errors.DockerException( 'Invalid device type {0}'.format(type(device)) ) @@ -403,20 +391,20 @@ def kwargs_from_env(ssl_version=None, assert_hostname=None, environment=None): def convert_filters(filters): result = {} - for k, v in iteritems(filters): + for k, v in filters.items(): if isinstance(v, bool): v = 'true' if v else 'false' if not isinstance(v, list): v = [v, ] result[k] = [ - str(item) if not isinstance(item, string_types) else item + str(item) if not isinstance(item, str) else item for item in v ] return json.dumps(result) def parse_bytes(s): - if isinstance(s, integer_types + (float,)): + if isinstance(s, (int, float)): return s if len(s) == 0: return 0 @@ -458,7 +446,7 @@ def parse_bytes(s): def normalize_links(links): if isinstance(links, dict): - links = iteritems(links) + links = links.items() return ['{0}:{1}'.format(k, v) if v else k for k, v in sorted(links)] @@ -493,8 +481,6 @@ def parse_env_file(env_file): def split_command(command): - if PY2 and not isinstance(command, binary_type): - command = command.encode('utf-8') return shlex.split(command) @@ -502,22 +488,22 @@ def format_environment(environment): def format_env(key, value): if value is None: return key - if isinstance(value, binary_type): + if isinstance(value, bytes): value = value.decode('utf-8') return u'{key}={value}'.format(key=key, value=value) - return [format_env(*var) for var in iteritems(environment)] + return [format_env(*var) for var in environment.items()] def format_extra_hosts(extra_hosts, task=False): # Use format dictated by Swarm API if container is part of a task if task: return [ - '{0} {1}'.format(v, k) for k, v in sorted(iteritems(extra_hosts)) + '{0} {1}'.format(v, k) for k, v in sorted(extra_hosts.items()) ] return [ - '{0}:{1}'.format(k, v) for k, v in sorted(iteritems(extra_hosts)) + '{0}:{1}'.format(k, v) for k, v in sorted(extra_hosts.items()) ] diff --git a/plugins/module_utils/_logfmt.py b/plugins/module_utils/_logfmt.py index fa45b575..73a2732d 100644 --- a/plugins/module_utils/_logfmt.py +++ b/plugins/module_utils/_logfmt.py @@ -8,8 +8,7 @@ Parse go logfmt messages. See https://pkg.go.dev/github.com/kr/logfmt?utm_source=godoc for information on the format. """ -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations # The format is defined in https://pkg.go.dev/github.com/kr/logfmt?utm_source=godoc diff --git a/plugins/module_utils/_platform.py b/plugins/module_utils/_platform.py index 4b6216f7..3460bdb5 100644 --- a/plugins/module_utils/_platform.py +++ b/plugins/module_utils/_platform.py @@ -8,8 +8,7 @@ # It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection) # SPDX-License-Identifier: Apache-2.0 -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import re diff --git a/plugins/module_utils/_scramble.py b/plugins/module_utils/_scramble.py index a9a6103d..3b82ab58 100644 --- a/plugins/module_utils/_scramble.py +++ b/plugins/module_utils/_scramble.py @@ -2,14 +2,12 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import base64 import random from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text -from ansible_collections.community.docker.plugins.module_utils._six import PY2 def generate_insecure_key(): @@ -17,10 +15,7 @@ def generate_insecure_key(): while True: # Generate a one-byte key. Right now the functions below do not use more # than one byte, so this is sufficient. - if PY2: - key = chr(random.randint(0, 255)) - else: - key = bytes([random.randint(0, 255)]) + key = bytes([random.randint(0, 255)]) # Return anything that is not zero if key != b'\x00': return key @@ -31,12 +26,8 @@ def scramble(value, key): if len(key) < 1: raise ValueError('Key must be at least one byte') value = to_bytes(value) - if PY2: - k = ord(key[0]) - value = b''.join([chr(k ^ ord(b)) for b in value]) - else: - k = key[0] - value = bytes([k ^ b for b in value]) + k = key[0] + value = bytes([k ^ b for b in value]) return '=S=' + to_native(base64.b64encode(value)) @@ -47,10 +38,6 @@ def unscramble(value, key): if not value.startswith(u'=S='): raise ValueError('Value does not start with indicator') value = base64.b64decode(value[3:]) - if PY2: - k = ord(key[0]) - value = b''.join([chr(k ^ ord(b)) for b in value]) - else: - k = key[0] - value = bytes([k ^ b for b in value]) + k = key[0] + value = bytes([k ^ b for b in value]) return to_text(value) diff --git a/plugins/module_utils/_six.py b/plugins/module_utils/_six.py deleted file mode 100644 index 1fa75508..00000000 --- a/plugins/module_utils/_six.py +++ /dev/null @@ -1,98 +0,0 @@ -# This code is strewn with things that are not defined on Python3 (unicode, -# long, etc) but they are all shielded by version checks. This is also an -# upstream vendored file that we're not going to modify on our own -# pylint: disable=undefined-variable -# -# Copyright (c) 2010-2024 Benjamin Peterson -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -# Extracted from https://github.com/benjaminp/six/blob/7d2a0e96602b83cd082896c8c224a87f1efe2111/six.py -# SPDX-License-Identifier: MIT - -from __future__ import absolute_import, division, print_function - - -__metaclass__ = type - -import sys as _sys - - -# Useful for very coarse version differentiation. -PY2 = _sys.version_info[0] == 2 -PY3 = _sys.version_info[0] > 2 - - -if PY3: - string_types = (str,) - integer_types = (int,) - binary_type = bytes - text_type = str - - def iteritems(d): - return d.items() - - from shlex import quote as shlex_quote # pylint: disable=unused-import - from collections.abc import Mapping, Sequence # pylint: disable=unused-import - from queue import Empty # pylint: disable=unused-import - from urllib.parse import quote, urlparse # pylint: disable=unused-import -else: - string_types = (basestring,) # noqa: F821, pylint: disable=undefined-variable - integer_types = (int, long) # noqa: F821, pylint: disable=undefined-variable - binary_type = str - text_type = unicode # noqa: F821, pylint: disable=undefined-variable - - def iteritems(d): - return d.iteritems() - - from pipes import quote as shlex_quote - from collections import Mapping, Sequence - from Queue import Empty - from urllib import quote - from urlparse import urlparse - -if PY3: - import builtins as _builtins - getattr(_builtins, "exec")("""def raise_from(value, from_value): - try: - raise value from from_value - finally: - value = None -""") -else: - def raise_from(value, from_value): - raise value - - -def add_metaclass(metaclass): - """Class decorator for creating a class with a metaclass.""" - def wrapper(cls): - orig_vars = cls.__dict__.copy() - slots = orig_vars.get('__slots__') - if slots is not None: - if isinstance(slots, str): - slots = [slots] - for slots_var in slots: - orig_vars.pop(slots_var) - orig_vars.pop('__dict__', None) - orig_vars.pop('__weakref__', None) - if hasattr(cls, '__qualname__'): - orig_vars['__qualname__'] = cls.__qualname__ - return metaclass(cls.__name__, cls.__bases__, orig_vars) - return wrapper diff --git a/plugins/module_utils/common.py b/plugins/module_utils/common.py index 57b10e88..7289e1c5 100644 --- a/plugins/module_utils/common.py +++ b/plugins/module_utils/common.py @@ -2,8 +2,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import abc @@ -12,9 +11,9 @@ import platform import re import sys import traceback +from collections.abc import Mapping, Sequence from ansible.module_utils.basic import AnsibleModule, missing_required_lib -from ansible_collections.community.docker.plugins.module_utils._six import Mapping, Sequence, string_types from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE, BOOLEANS_FALSE from ansible_collections.community.docker.plugins.module_utils.version import LooseVersion @@ -209,10 +208,8 @@ class AnsibleDockerClientBase(Client): "state." % (platform.node(), sys.executable)) if not HAS_DOCKER_PY: - msg = missing_required_lib("Docker SDK for Python: docker>=5.0.0 (Python >= 3.6) or " - "docker<5.0.0 (Python 2.7)") - msg = msg + ", for example via `pip install docker` (Python >= 3.6) or " \ - + "`pip install docker==4.4.4` (Python 2.7). The error was: %s" + msg = missing_required_lib("Docker SDK for Python: docker>=5.0.0") + msg = msg + ", for example via `pip install docker`. The error was: %s" self.fail(msg % HAS_DOCKER_ERROR, exception=HAS_DOCKER_TRACEBACK) if self.docker_py_version < LooseVersion(min_docker_version): @@ -695,5 +692,5 @@ class AnsibleDockerClient(AnsibleDockerClientBase): if isinstance(result, Sequence): for warning in result: self.module.warn('Docker warning: {0}'.format(warning)) - elif isinstance(result, string_types) and result: + elif isinstance(result, str) and result: self.module.warn('Docker warning: {0}'.format(result)) diff --git a/plugins/module_utils/common_api.py b/plugins/module_utils/common_api.py index f2439bd6..1da8ad19 100644 --- a/plugins/module_utils/common_api.py +++ b/plugins/module_utils/common_api.py @@ -3,16 +3,15 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import abc import os import re +from collections.abc import Mapping, Sequence from ansible.module_utils.basic import AnsibleModule, missing_required_lib -from ansible_collections.community.docker.plugins.module_utils._six import Mapping, Sequence, string_types from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE, BOOLEANS_FALSE from ansible_collections.community.docker.plugins.module_utils.version import LooseVersion @@ -579,5 +578,5 @@ class AnsibleDockerClient(AnsibleDockerClientBase): if isinstance(result, Sequence): for warning in result: self.module.warn('Docker warning: {0}'.format(warning)) - elif isinstance(result, string_types) and result: + elif isinstance(result, str) and result: self.module.warn('Docker warning: {0}'.format(result)) diff --git a/plugins/module_utils/common_cli.py b/plugins/module_utils/common_cli.py index ae175f2f..1cdc788c 100644 --- a/plugins/module_utils/common_cli.py +++ b/plugins/module_utils/common_cli.py @@ -2,8 +2,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import abc @@ -13,7 +12,6 @@ import shlex from ansible.module_utils.basic import AnsibleModule, env_fallback from ansible.module_utils.common.process import get_bin_path from ansible.module_utils.common.text.converters import to_native -from ansible_collections.community.docker.plugins.module_utils._six import string_types from ansible_collections.community.docker.plugins.module_utils.version import LooseVersion @@ -86,7 +84,7 @@ class AnsibleDockerClientBase(object): self._info = None if needs_api_version: - if not isinstance(self._version.get('Server'), dict) or not isinstance(self._version['Server'].get('ApiVersion'), string_types): + if not isinstance(self._version.get('Server'), dict) or not isinstance(self._version['Server'].get('ApiVersion'), str): self.fail('Cannot determine Docker Daemon information. Are you maybe using podman instead of docker?') self.docker_api_version_str = to_native(self._version['Server']['ApiVersion']) self.docker_api_version = LooseVersion(self.docker_api_version_str) @@ -118,9 +116,7 @@ class AnsibleDockerClientBase(object): return ' '.join(shlex.quote(a) for a in self._compose_cmd(args)) @abc.abstractmethod - # def call_cli(self, *args, check_rc=False, data=None, cwd=None, environ_update=None): - def call_cli(self, *args, **kwargs): - # Python 2.7 does not like anything than '**kwargs' after '*args', so we have to do this manually... + def call_cli(self, *args, check_rc=False, data=None, cwd=None, environ_update=None): pass # def call_cli_json(self, *args, check_rc=False, data=None, cwd=None, environ_update=None, warn_on_stderr=False): @@ -320,16 +316,7 @@ class AnsibleModuleDockerClient(AnsibleDockerClientBase): common_args, min_docker_api_version=min_docker_api_version, needs_api_version=needs_api_version, ) - # def call_cli(self, *args, check_rc=False, data=None, cwd=None, environ_update=None): - def call_cli(self, *args, **kwargs): - # Python 2.7 does not like anything than '**kwargs' after '*args', so we have to do this manually... - check_rc = kwargs.pop('check_rc', False) - data = kwargs.pop('data', None) - cwd = kwargs.pop('cwd', None) - environ_update = kwargs.pop('environ_update', None) - if kwargs: - raise TypeError("call_cli() got an unexpected keyword argument '%s'" % list(kwargs)[0]) - + def call_cli(self, *args, check_rc=False, data=None, cwd=None, environ_update=None): environment = self._environment.copy() if environ_update: environment.update(environ_update) diff --git a/plugins/module_utils/compose_v2.py b/plugins/module_utils/compose_v2.py index 6e6ad39f..75d0ce80 100644 --- a/plugins/module_utils/compose_v2.py +++ b/plugins/module_utils/compose_v2.py @@ -3,8 +3,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import json @@ -14,10 +13,10 @@ import shutil import tempfile import traceback from collections import namedtuple +from shlex import quote from ansible.module_utils.basic import missing_required_lib from ansible.module_utils.common.text.converters import to_native -from ansible_collections.community.docker.plugins.module_utils._six import shlex_quote, string_types from ansible_collections.community.docker.plugins.module_utils.util import DockerBaseClass from ansible_collections.community.docker.plugins.module_utils.version import LooseVersion @@ -461,7 +460,7 @@ def parse_json_events(stderr, warn_function=None): elif text in DOCKER_PULL_PROGRESS_DONE or line_data.get('text') in DOCKER_PULL_PROGRESS_WORKING: resource_type = ResourceType.IMAGE_LAYER status, text = text, status - elif status is None and isinstance(text, string_types) and text.startswith('Skipped - '): + elif status is None and isinstance(text, str) and text.startswith('Skipped - '): status, text = text.split(' - ', 1) elif line_data.get('level') in _JSON_LEVEL_TO_STATUS_MAP and 'msg' in line_data: status = _JSON_LEVEL_TO_STATUS_MAP[line_data['level']] @@ -629,7 +628,7 @@ def update_failed(result, events, args, stdout, stderr, rc, cli): errors.append('Return code {code} is non-zero'.format(code=rc)) result['failed'] = True result['msg'] = '\n'.join(errors) - result['cmd'] = ' '.join(shlex_quote(arg) for arg in [cli] + args) + result['cmd'] = ' '.join(quote(arg) for arg in [cli] + args) result['stdout'] = to_native(stdout) result['stderr'] = to_native(stderr) result['rc'] = rc diff --git a/plugins/module_utils/copy.py b/plugins/module_utils/copy.py index 1e736a2e..fd1fa20d 100644 --- a/plugins/module_utils/copy.py +++ b/plugins/module_utils/copy.py @@ -2,8 +2,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import base64 import datetime @@ -16,7 +15,6 @@ import stat import tarfile from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text -from ansible_collections.community.docker.plugins.module_utils._six import raise_from from ansible_collections.community.docker.plugins.module_utils._api.errors import APIError, NotFound @@ -126,12 +124,7 @@ def _regular_content_tar_generator(content, out_file, user_id, group_id, mode, u tarinfo.uid = user_id tarinfo.gid = group_id tarinfo.size = len(content) - try: - tarinfo.mtime = int(datetime.datetime.now().timestamp()) - except AttributeError: - # Python 2 (or more precisely: Python < 3.3) has no timestamp(). Use the following - # expression for Python 2: - tarinfo.mtime = int((datetime.datetime.utcnow() - datetime.datetime(1970, 1, 1)).total_seconds()) + tarinfo.mtime = int(datetime.datetime.now().timestamp()) tarinfo.type = tarfile.REGTYPE tarinfo.linkname = '' if user_name: @@ -346,9 +339,9 @@ def fetch_file(client, container, in_path, out_path, follow_links=False, log=Non if not follow_links and os.path.exists(b_out_path): os.unlink(b_out_path) - in_f = tar.extractfile(member) # in Python 2, this *cannot* be used in `with`... - with open(b_out_path, 'wb') as out_f: - shutil.copyfileobj(in_f, out_f) + with tar.extractfile(member) as in_f: + with open(b_out_path, 'wb') as out_f: + shutil.copyfileobj(in_f, out_f) return in_path def process_symlink(in_path, member): @@ -385,16 +378,10 @@ def _execute_command(client, container, command, log=None, check_rc=False): try: exec_data = client.post_json_to_json('/containers/{0}/exec', container, data=data) except NotFound as e: - raise_from( - DockerFileCopyError('Could not find container "{container}"'.format(container=container)), - e, - ) + raise DockerFileCopyError('Could not find container "{container}"'.format(container=container)) from e except APIError as e: if e.response is not None and e.response.status_code == 409: - raise_from( - DockerFileCopyError('Cannot execute command in paused container "{container}"'.format(container=container)), - e, - ) + raise DockerFileCopyError('Cannot execute command in paused container "{container}"'.format(container=container)) from e raise exec_id = exec_data['Id'] diff --git a/plugins/module_utils/image_archive.py b/plugins/module_utils/image_archive.py index cad8e832..014e0f87 100644 --- a/plugins/module_utils/image_archive.py +++ b/plugins/module_utils/image_archive.py @@ -2,8 +2,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import json import os @@ -31,18 +30,7 @@ class ImageArchiveManifestSummary(object): class ImageArchiveInvalidException(Exception): - def __init__(self, message, cause): - ''' - :param message: Exception message - :type message: str - :param cause: Inner exception that this exception wraps - :type cause: Exception | None - ''' - - super(ImageArchiveInvalidException, self).__init__(message) - - # Python 2 does not support causes - self.cause = cause + pass def api_image_id(archive_image_id): @@ -84,26 +72,19 @@ def load_archived_image_manifest(archive_path): if not os.path.isfile(archive_path): return None - tf = tarfile.open(archive_path, 'r') - try: + with tarfile.open(archive_path, 'r') as tf: try: - ef = tf.extractfile('manifest.json') try: - text = ef.read().decode('utf-8') - manifest = json.loads(text) + with tf.extractfile('manifest.json') as ef: + manifest = json.load(ef) except Exception as exc: raise ImageArchiveInvalidException( - "Failed to decode and deserialize manifest.json: %s" % to_native(exc), - exc - ) - finally: - # In Python 2.6, this does not have __exit__ - ef.close() + "Failed to decode and deserialize manifest.json: %s" % to_native(exc) + ) from exc if len(manifest) == 0: raise ImageArchiveInvalidException( - "Expected to have at least one entry in manifest.json but found none", - None + "Expected to have at least one entry in manifest.json but found none" ) result = [] @@ -112,9 +93,8 @@ def load_archived_image_manifest(archive_path): config_file = meta['Config'] except KeyError as exc: raise ImageArchiveInvalidException( - "Failed to get Config entry from {0}th manifest in manifest.json: {1}".format(index + 1, to_native(exc)), - exc - ) + "Failed to get Config entry from {0}th manifest in manifest.json: {1}".format(index + 1, to_native(exc)) + ) from exc # Extracts hash without 'sha256:' prefix try: @@ -122,9 +102,8 @@ def load_archived_image_manifest(archive_path): image_id = os.path.splitext(config_file)[0] except Exception as exc: raise ImageArchiveInvalidException( - "Failed to extract image id from config file name %s: %s" % (config_file, to_native(exc)), - exc - ) + "Failed to extract image id from config file name %s: %s" % (config_file, to_native(exc)) + ) from exc for prefix in ( 'blobs/sha256/', # Moby 25.0.0, Docker API 1.44 @@ -136,9 +115,8 @@ def load_archived_image_manifest(archive_path): repo_tags = meta['RepoTags'] except KeyError as exc: raise ImageArchiveInvalidException( - "Failed to get RepoTags entry from {0}th manifest in manifest.json: {1}".format(index + 1, to_native(exc)), - exc - ) + "Failed to get RepoTags entry from {0}th manifest in manifest.json: {1}".format(index + 1, to_native(exc)) + ) from exc result.append(ImageArchiveManifestSummary( image_id=image_id, @@ -150,18 +128,13 @@ def load_archived_image_manifest(archive_path): raise except Exception as exc: raise ImageArchiveInvalidException( - "Failed to extract manifest.json from tar file %s: %s" % (archive_path, to_native(exc)), - exc - ) - - finally: - # In Python 2.6, TarFile does not have __exit__ - tf.close() + "Failed to extract manifest.json from tar file %s: %s" % (archive_path, to_native(exc)) + ) from exc except ImageArchiveInvalidException: raise except Exception as exc: - raise ImageArchiveInvalidException("Failed to open tar file %s: %s" % (archive_path, to_native(exc)), exc) + raise ImageArchiveInvalidException("Failed to open tar file %s: %s" % (archive_path, to_native(exc))) from exc def archived_image_manifest(archive_path): @@ -189,6 +162,5 @@ def archived_image_manifest(archive_path): if len(results) == 1: return results[0] raise ImageArchiveInvalidException( - "Expected to have one entry in manifest.json but found %s" % len(results), - None + "Expected to have one entry in manifest.json but found %s" % len(results) ) diff --git a/plugins/module_utils/module_container/base.py b/plugins/module_utils/module_container/base.py index 3870dac9..f4dc5af1 100644 --- a/plugins/module_utils/module_container/base.py +++ b/plugins/module_utils/module_container/base.py @@ -3,8 +3,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations import abc import os @@ -15,7 +14,6 @@ from functools import partial from ansible.module_utils.common.text.converters import to_native, to_text from ansible.module_utils.common.text.formatters import human_to_bytes -from ansible_collections.community.docker.plugins.module_utils._six import string_types from ansible_collections.community.docker.plugins.module_utils.util import ( clean_dict_booleans_for_docker_api, @@ -461,7 +459,7 @@ def _preprocess_env(module, values): final_env[name] = to_text(value, errors='surrogate_or_strict') if 'env' in values: for name, value in values['env'].items(): - if not isinstance(value, string_types): + if not isinstance(value, str): module.fail_json(msg='Non-string value found for env option. Ambiguous env options must be ' 'wrapped in quotes to avoid them being interpreted. Key: %s' % (name, )) final_env[name] = to_text(value, errors='surrogate_or_strict') @@ -695,7 +693,7 @@ def _preprocess_log(module, values): if 'log_options' in values: options = {} for k, v in values['log_options'].items(): - if not isinstance(v, string_types): + if not isinstance(v, str): module.warn( "Non-string value found for log_options option '%s'. The value is automatically converted to '%s'. " "If this is not correct, or you want to avoid such warnings, please quote the value." % ( @@ -780,7 +778,7 @@ def _preprocess_ports(module, values): # Any published port should also be exposed for publish_port in values['published_ports']: match = False - if isinstance(publish_port, string_types) and '/' in publish_port: + if isinstance(publish_port, str) and '/' in publish_port: port, protocol = publish_port.split('/') port = int(port) else: @@ -789,7 +787,7 @@ def _preprocess_ports(module, values): for exposed_port in exposed: if exposed_port[1] != protocol: continue - if isinstance(exposed_port[0], string_types) and '-' in exposed_port[0]: + if isinstance(exposed_port[0], str) and '-' in exposed_port[0]: start_port, end_port = exposed_port[0].split('-') if int(start_port) <= port <= int(end_port): match = True diff --git a/plugins/module_utils/module_container/docker_api.py b/plugins/module_utils/module_container/docker_api.py index d44368e0..bc2129a4 100644 --- a/plugins/module_utils/module_container/docker_api.py +++ b/plugins/module_utils/module_container/docker_api.py @@ -3,8 +3,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations import json import traceback diff --git a/plugins/module_utils/module_container/module.py b/plugins/module_utils/module_container/module.py index 206f972d..e68a8df4 100644 --- a/plugins/module_utils/module_container/module.py +++ b/plugins/module_utils/module_container/module.py @@ -3,8 +3,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations import re from time import sleep diff --git a/plugins/module_utils/selectors.py b/plugins/module_utils/selectors.py index ca52cc87..fcb48e63 100644 --- a/plugins/module_utils/selectors.py +++ b/plugins/module_utils/selectors.py @@ -6,16 +6,7 @@ """Provide selectors import.""" -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations -# Once we drop support for ansible-core 2.16, we can remove the try/except. - -from sys import version_info as _python_version_info - - -if _python_version_info < (3, 4): - from ansible.module_utils.compat import selectors # noqa: F401, pylint: disable=unused-import -else: - import selectors # noqa: F401, pylint: disable=unused-import +import selectors # noqa: F401, pylint: disable=unused-import diff --git a/plugins/module_utils/socket_handler.py b/plugins/module_utils/socket_handler.py index 59c575a3..27d8a3eb 100644 --- a/plugins/module_utils/socket_handler.py +++ b/plugins/module_utils/socket_handler.py @@ -2,8 +2,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import os @@ -11,8 +10,6 @@ import os.path import socket as pysocket import struct -from ansible_collections.community.docker.plugins.module_utils._six import PY2 - from ansible_collections.community.docker.plugins.module_utils._api.utils import socket as docker_socket from ansible_collections.community.docker.plugins.module_utils.socket_helper import ( @@ -85,7 +82,7 @@ class DockerSocketHandlerBase(object): return else: raise - elif not PY2 and isinstance(self._sock, getattr(pysocket, 'SocketIO')): + elif isinstance(self._sock, getattr(pysocket, 'SocketIO')): data = self._sock.read() else: data = os.read(self._sock.fileno()) diff --git a/plugins/module_utils/socket_helper.py b/plugins/module_utils/socket_helper.py index f8df2bdf..c0a54807 100644 --- a/plugins/module_utils/socket_helper.py +++ b/plugins/module_utils/socket_helper.py @@ -2,8 +2,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import fcntl @@ -11,8 +10,6 @@ import os import os.path import socket as pysocket -from ansible_collections.community.docker.plugins.module_utils._six import PY2 - def make_file_unblocking(file): fcntl.fcntl(file.fileno(), fcntl.F_SETFL, fcntl.fcntl(file.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK) @@ -49,7 +46,7 @@ def shutdown_writing(sock, log=_empty_writer): # probably: "TypeError: shutdown() takes 1 positional argument but 2 were given" log('Shutting down for writing not possible; trying shutdown instead: {0}'.format(e)) sock.shutdown() - elif not PY2 and isinstance(sock, getattr(pysocket, 'SocketIO')): + elif isinstance(sock, getattr(pysocket, 'SocketIO')): sock._sock.shutdown(pysocket.SHUT_WR) else: log('No idea how to signal end of writing') diff --git a/plugins/module_utils/swarm.py b/plugins/module_utils/swarm.py index 0dbc1e72..23b90ce8 100644 --- a/plugins/module_utils/swarm.py +++ b/plugins/module_utils/swarm.py @@ -3,8 +3,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import json diff --git a/plugins/module_utils/util.py b/plugins/module_utils/util.py index cbffc47e..2eca037d 100644 --- a/plugins/module_utils/util.py +++ b/plugins/module_utils/util.py @@ -2,17 +2,16 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import json import re from datetime import timedelta +from urllib.parse import urlparse from ansible.module_utils.basic import env_fallback from ansible.module_utils.common.collections import is_sequence -from ansible_collections.community.docker.plugins.module_utils._six import string_types, urlparse from ansible.module_utils.common.text.converters import to_text @@ -289,7 +288,7 @@ def sanitize_labels(labels, labels_field, client=None, module=None): if labels is None: return for k, v in list(labels.items()): - if not isinstance(k, string_types): + if not isinstance(k, str): fail( "The key {key!r} of {field} is not a string!".format( field=labels_field, key=k)) diff --git a/plugins/module_utils/version.py b/plugins/module_utils/version.py index 586b694b..be22eeae 100644 --- a/plugins/module_utils/version.py +++ b/plugins/module_utils/version.py @@ -6,8 +6,7 @@ """Provide version object to compare version numbers.""" -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations from ansible.module_utils.compat.version import LooseVersion, StrictVersion # noqa: F401, pylint: disable=unused-import diff --git a/plugins/modules/current_container_facts.py b/plugins/modules/current_container_facts.py index a376baca..6f502891 100644 --- a/plugins/modules/current_container_facts.py +++ b/plugins/modules/current_container_facts.py @@ -5,8 +5,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_compose_v2.py b/plugins/modules/docker_compose_v2.py index 72350736..b27fec08 100644 --- a/plugins/modules/docker_compose_v2.py +++ b/plugins/modules/docker_compose_v2.py @@ -6,8 +6,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" @@ -441,7 +440,6 @@ import traceback from ansible.module_utils.common.validation import check_type_int from ansible.module_utils.common.text.converters import to_native -from ansible_collections.community.docker.plugins.module_utils._six import string_types from ansible_collections.community.docker.plugins.module_utils.common_cli import ( AnsibleModuleDockerClient, @@ -482,7 +480,7 @@ class ServicesManager(BaseComposeManager): self.fail('assume_yes=true needs Docker Compose 2.32.0 or newer, not version %s' % (self.compose_version, )) for key, value in self.scale.items(): - if not isinstance(key, string_types): + if not isinstance(key, str): self.fail('The key %s for `scale` is not a string' % repr(key)) try: value = check_type_int(value) diff --git a/plugins/modules/docker_compose_v2_exec.py b/plugins/modules/docker_compose_v2_exec.py index 13fcab0c..8f88e798 100644 --- a/plugins/modules/docker_compose_v2_exec.py +++ b/plugins/modules/docker_compose_v2_exec.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" @@ -169,7 +168,6 @@ import shlex import traceback from ansible.module_utils.common.text.converters import to_text, to_native -from ansible_collections.community.docker.plugins.module_utils._six import string_types from ansible_collections.community.docker.plugins.module_utils.common_cli import ( AnsibleModuleDockerClient, @@ -210,7 +208,7 @@ class ExecManager(BaseComposeManager): if self.env is not None: for name, value in list(self.env.items()): - if not isinstance(value, string_types): + if not isinstance(value, str): self.fail( "Non-string value found for env option. Ambiguous env options must be " "wrapped in quotes to avoid them being interpreted. Key: %s" % (name, ) diff --git a/plugins/modules/docker_compose_v2_pull.py b/plugins/modules/docker_compose_v2_pull.py index 9d4dbdb2..d5dbbd7c 100644 --- a/plugins/modules/docker_compose_v2_pull.py +++ b/plugins/modules/docker_compose_v2_pull.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_compose_v2_run.py b/plugins/modules/docker_compose_v2_run.py index b9352404..efc0f907 100644 --- a/plugins/modules/docker_compose_v2_run.py +++ b/plugins/modules/docker_compose_v2_run.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" @@ -242,7 +241,6 @@ import shlex import traceback from ansible.module_utils.common.text.converters import to_text, to_native -from ansible_collections.community.docker.plugins.module_utils._six import string_types from ansible_collections.community.docker.plugins.module_utils.common_cli import ( AnsibleModuleDockerClient, @@ -296,7 +294,7 @@ class ExecManager(BaseComposeManager): if self.env is not None: for name, value in list(self.env.items()): - if not isinstance(value, string_types): + if not isinstance(value, str): self.fail( "Non-string value found for env option. Ambiguous env options must be " "wrapped in quotes to avoid them being interpreted. Key: %s" % (name, ) diff --git a/plugins/modules/docker_config.py b/plugins/modules/docker_config.py index b6fe3cf1..db1e8b64 100644 --- a/plugins/modules/docker_config.py +++ b/plugins/modules/docker_config.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_container.py b/plugins/modules/docker_container.py index 86b6dbdd..47b32562 100644 --- a/plugins/modules/docker_container.py +++ b/plugins/modules/docker_container.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_container_copy_into.py b/plugins/modules/docker_container_copy_into.py index 0a95e4c5..5060cdb3 100644 --- a/plugins/modules/docker_container_copy_into.py +++ b/plugins/modules/docker_container_copy_into.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" @@ -173,7 +172,6 @@ import traceback from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text from ansible.module_utils.common.validation import check_type_int -from ansible_collections.community.docker.plugins.module_utils._six import integer_types, string_types from ansible_collections.community.docker.plugins.module_utils._api.errors import APIError, DockerException, NotFound @@ -421,8 +419,9 @@ def add_diff_dst_from_regular_member(diff, max_file_size_for_diff, container_pat diff['dst_larger'] = max_file_size_for_diff return - tar_f = tar.extractfile(member) # in Python 2, this *cannot* be used in `with`... - content = tar_f.read() + with tar.extractfile(member) as tar_f: + content = tar_f.read() + if is_binary(content): diff['dst_binary'] = 1 else: @@ -546,9 +545,9 @@ def is_file_idempotent(client, container, managed_path, container_path, follow_l add_diff_dst_from_regular_member(diff, max_file_size_for_diff, in_path, tar, member) return container_path, mode, False - tar_f = tar.extractfile(member) # in Python 2, this *cannot* be used in `with`... - with open(managed_path, 'rb') as local_f: - is_equal = are_fileobjs_equal_with_diff_of_first(tar_f, local_f, member.size, diff, max_file_size_for_diff, in_path) + with tar.extractfile(member) as tar_f: + with open(managed_path, 'rb') as local_f: + is_equal = are_fileobjs_equal_with_diff_of_first(tar_f, local_f, member.size, diff, max_file_size_for_diff, in_path) return container_path, mode, is_equal def process_symlink(in_path, member): @@ -707,8 +706,8 @@ def is_content_idempotent(client, container, content, container_path, follow_lin add_diff_dst_from_regular_member(diff, max_file_size_for_diff, in_path, tar, member) return container_path, mode, False - tar_f = tar.extractfile(member) # in Python 2, this *cannot* be used in `with`... - is_equal = are_fileobjs_equal_with_diff_of_first(tar_f, io.BytesIO(content), member.size, diff, max_file_size_for_diff, in_path) + with tar.extractfile(member) as tar_f: + is_equal = are_fileobjs_equal_with_diff_of_first(tar_f, io.BytesIO(content), member.size, diff, max_file_size_for_diff, in_path) return container_path, mode, is_equal def process_symlink(in_path, member): @@ -783,15 +782,15 @@ def copy_content_into_container(client, container, content, container_path, foll def parse_modern(mode): - if isinstance(mode, string_types): + if isinstance(mode, str): return int(to_native(mode), 8) - if isinstance(mode, integer_types): + if isinstance(mode, int): return mode raise TypeError('must be an octal string or an integer, got {mode!r}'.format(mode=mode)) def parse_octal_string_only(mode): - if isinstance(mode, string_types): + if isinstance(mode, str): return int(to_native(mode), 8) raise TypeError('must be an octal string, got {mode!r}'.format(mode=mode)) diff --git a/plugins/modules/docker_container_exec.py b/plugins/modules/docker_container_exec.py index f1ad9219..1e9e2779 100644 --- a/plugins/modules/docker_container_exec.py +++ b/plugins/modules/docker_container_exec.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" @@ -164,19 +163,17 @@ exec_id: version_added: 2.1.0 """ +import selectors import shlex import traceback from ansible.module_utils.common.text.converters import to_text, to_bytes, to_native -from ansible_collections.community.docker.plugins.module_utils._six import string_types from ansible_collections.community.docker.plugins.module_utils.common_api import ( AnsibleDockerClient, RequestException, ) -from ansible_collections.community.docker.plugins.module_utils.selectors import selectors - from ansible_collections.community.docker.plugins.module_utils.socket_handler import ( DockerSocketHandlerModule, ) @@ -228,7 +225,7 @@ def main(): if env is not None: for name, value in list(env.items()): - if not isinstance(value, string_types): + if not isinstance(value, str): client.module.fail_json( msg="Non-string value found for env option. Ambiguous env options must be " "wrapped in quotes to avoid them being interpreted. Key: %s" % (name, )) diff --git a/plugins/modules/docker_container_info.py b/plugins/modules/docker_container_info.py index abb94bd2..0028fcc7 100644 --- a/plugins/modules/docker_container_info.py +++ b/plugins/modules/docker_container_info.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_context_info.py b/plugins/modules/docker_context_info.py index 04e99680..30b466e8 100644 --- a/plugins/modules/docker_context_info.py +++ b/plugins/modules/docker_context_info.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" @@ -177,7 +176,6 @@ import traceback from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.common.text.converters import to_native, to_text -from ansible_collections.community.docker.plugins.module_utils._six import string_types from ansible_collections.community.docker.plugins.module_utils._api.context.api import ( ContextAPI, @@ -214,7 +212,7 @@ def context_to_json(context, current): module_config = {} if 'docker' in context.endpoints: endpoint = context.endpoints['docker'] - if isinstance(endpoint.get('Host'), string_types): + if isinstance(endpoint.get('Host'), str): host_str = to_text(endpoint['Host']) # Adjust protocol name so that it works with the Docker CLI tool as well diff --git a/plugins/modules/docker_host_info.py b/plugins/modules/docker_host_info.py index 99181676..76f612d1 100644 --- a/plugins/modules/docker_host_info.py +++ b/plugins/modules/docker_host_info.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_image.py b/plugins/modules/docker_image.py index dd17a6f4..57a7c090 100644 --- a/plugins/modules/docker_image.py +++ b/plugins/modules/docker_image.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_image_build.py b/plugins/modules/docker_image_build.py index 298f2927..d83549df 100644 --- a/plugins/modules/docker_image_build.py +++ b/plugins/modules/docker_image_build.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_image_export.py b/plugins/modules/docker_image_export.py index 23997f41..85161d29 100644 --- a/plugins/modules/docker_image_export.py +++ b/plugins/modules/docker_image_export.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_image_info.py b/plugins/modules/docker_image_info.py index ef299233..6671d5f1 100644 --- a/plugins/modules/docker_image_info.py +++ b/plugins/modules/docker_image_info.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_image_load.py b/plugins/modules/docker_image_load.py index f8fd3f8c..5d6376e1 100644 --- a/plugins/modules/docker_image_load.py +++ b/plugins/modules/docker_image_load.py @@ -5,8 +5,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_image_pull.py b/plugins/modules/docker_image_pull.py index 2ba98f35..d62c428f 100644 --- a/plugins/modules/docker_image_pull.py +++ b/plugins/modules/docker_image_pull.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_image_push.py b/plugins/modules/docker_image_push.py index 89ba1e31..ee75f270 100644 --- a/plugins/modules/docker_image_push.py +++ b/plugins/modules/docker_image_push.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_image_remove.py b/plugins/modules/docker_image_remove.py index 815355cf..23d3f795 100644 --- a/plugins/modules/docker_image_remove.py +++ b/plugins/modules/docker_image_remove.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_image_tag.py b/plugins/modules/docker_image_tag.py index 5c8fd02b..3001bbc8 100644 --- a/plugins/modules/docker_image_tag.py +++ b/plugins/modules/docker_image_tag.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_login.py b/plugins/modules/docker_login.py index 458c57a2..22d5add8 100644 --- a/plugins/modules/docker_login.py +++ b/plugins/modules/docker_login.py @@ -7,8 +7,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_network.py b/plugins/modules/docker_network.py index db81a281..a9bd04fd 100644 --- a/plugins/modules/docker_network.py +++ b/plugins/modules/docker_network.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_network_info.py b/plugins/modules/docker_network_info.py index 53fca2d1..b07a4133 100644 --- a/plugins/modules/docker_network_info.py +++ b/plugins/modules/docker_network_info.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_node.py b/plugins/modules/docker_node.py index 07915120..bf5c8f89 100644 --- a/plugins/modules/docker_node.py +++ b/plugins/modules/docker_node.py @@ -4,9 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function - -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" module: docker_node diff --git a/plugins/modules/docker_node_info.py b/plugins/modules/docker_node_info.py index 3e4880d8..9f6c7bf3 100644 --- a/plugins/modules/docker_node_info.py +++ b/plugins/modules/docker_node_info.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_plugin.py b/plugins/modules/docker_plugin.py index 135ec7dc..3b07d208 100644 --- a/plugins/modules/docker_plugin.py +++ b/plugins/modules/docker_plugin.py @@ -6,8 +6,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_prune.py b/plugins/modules/docker_prune.py index 7522e64e..645f50e4 100644 --- a/plugins/modules/docker_prune.py +++ b/plugins/modules/docker_prune.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_secret.py b/plugins/modules/docker_secret.py index dcb8cbe8..86a38e64 100644 --- a/plugins/modules/docker_secret.py +++ b/plugins/modules/docker_secret.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_stack.py b/plugins/modules/docker_stack.py index 21917865..b6b98621 100644 --- a/plugins/modules/docker_stack.py +++ b/plugins/modules/docker_stack.py @@ -5,8 +5,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" @@ -161,7 +160,6 @@ import os import tempfile import traceback -from ansible_collections.community.docker.plugins.module_utils._six import string_types from time import sleep from ansible.module_utils.common.text.converters import to_native @@ -280,7 +278,7 @@ def main(): with os.fdopen(compose_file_fd, 'w') as stack_file: compose_files.append(compose_file) stack_file.write(yaml_dump(compose_def)) - elif isinstance(compose_def, string_types): + elif isinstance(compose_def, str): compose_files.append(compose_def) else: client.fail("compose element '%s' must be a string or a dictionary" % compose_def) diff --git a/plugins/modules/docker_stack_info.py b/plugins/modules/docker_stack_info.py index 7ec2fbad..a5f7fc82 100644 --- a/plugins/modules/docker_stack_info.py +++ b/plugins/modules/docker_stack_info.py @@ -5,9 +5,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) - -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" module: docker_stack_info diff --git a/plugins/modules/docker_stack_task_info.py b/plugins/modules/docker_stack_task_info.py index 150f2a9c..6d9a7fb9 100644 --- a/plugins/modules/docker_stack_task_info.py +++ b/plugins/modules/docker_stack_task_info.py @@ -5,9 +5,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) - -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" module: docker_stack_task_info diff --git a/plugins/modules/docker_swarm.py b/plugins/modules/docker_swarm.py index 202a0cff..ab2cae8e 100644 --- a/plugins/modules/docker_swarm.py +++ b/plugins/modules/docker_swarm.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" module: docker_swarm diff --git a/plugins/modules/docker_swarm_info.py b/plugins/modules/docker_swarm_info.py index f87adc29..5d2acd4d 100644 --- a/plugins/modules/docker_swarm_info.py +++ b/plugins/modules/docker_swarm_info.py @@ -4,9 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function - -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" module: docker_swarm_info diff --git a/plugins/modules/docker_swarm_service.py b/plugins/modules/docker_swarm_service.py index 9a5b8c06..22947b6c 100644 --- a/plugins/modules/docker_swarm_service.py +++ b/plugins/modules/docker_swarm_service.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" module: docker_swarm_service @@ -870,7 +869,6 @@ from ansible_collections.community.docker.plugins.module_utils.util import ( ) from ansible.module_utils.basic import human_to_bytes -from ansible_collections.community.docker.plugins.module_utils._six import string_types from ansible.module_utils.common.text.converters import to_text, to_native try: @@ -904,11 +902,11 @@ def get_docker_environment(env, env_files): parsed_env_file = parse_env_file(env_file) for name, value in parsed_env_file.items(): env_dict[name] = str(value) - if env is not None and isinstance(env, string_types): + if env is not None and isinstance(env, str): env = env.split(',') if env is not None and isinstance(env, dict): for name, value in env.items(): - if not isinstance(value, string_types): + if not isinstance(value, str): raise ValueError( 'Non-string value found for env option. ' 'Ambiguous env options must be wrapped in quotes to avoid YAML parsing. Key: %s' % name @@ -943,7 +941,7 @@ def get_docker_networks(networks, network_ids): return None parsed_networks = [] for network in networks: - if isinstance(network, string_types): + if isinstance(network, str): parsed_network = {'name': network} elif isinstance(network, dict): if 'name' not in network: @@ -957,7 +955,7 @@ def get_docker_networks(networks, network_ids): if not isinstance(aliases, list): raise TypeError('"aliases" network option is only allowed as a list') if not all( - isinstance(alias, string_types) for alias in aliases + isinstance(alias, str) for alias in aliases ): raise TypeError('Only strings are allowed as network aliases.') parsed_network['aliases'] = aliases @@ -991,7 +989,7 @@ def get_nanoseconds_from_raw_option(name, value): return None elif isinstance(value, int): return value - elif isinstance(value, string_types): + elif isinstance(value, str): try: return int(value) except ValueError: @@ -1070,7 +1068,7 @@ def has_list_changed(new_list, old_list, sort_lists=True, sort_key=None): for new_item, old_item in zip_data: is_same_type = type(new_item) == type(old_item) # noqa: E721, pylint: disable=unidiomatic-typecheck if not is_same_type: - if isinstance(new_item, string_types) and isinstance(old_item, string_types): + if isinstance(new_item, str) and isinstance(old_item, str): # Even though the types are different between these items, # they are both strings. Try matching on the same string type. try: @@ -1474,13 +1472,13 @@ class DockerService(DockerBaseClass): s.networks = get_docker_networks(ap['networks'], network_ids) s.command = ap['command'] - if isinstance(s.command, string_types): + if isinstance(s.command, str): s.command = shlex.split(s.command) elif isinstance(s.command, list): invalid_items = [ (index, item) for index, item in enumerate(s.command) - if not isinstance(item, string_types) + if not isinstance(item, str) ] if invalid_items: errors = ', '.join( diff --git a/plugins/modules/docker_swarm_service_info.py b/plugins/modules/docker_swarm_service_info.py index 07c79bd9..eba7a29c 100644 --- a/plugins/modules/docker_swarm_service_info.py +++ b/plugins/modules/docker_swarm_service_info.py @@ -4,8 +4,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/modules/docker_volume.py b/plugins/modules/docker_volume.py index abf5b76f..35d8e43f 100644 --- a/plugins/modules/docker_volume.py +++ b/plugins/modules/docker_volume.py @@ -5,8 +5,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" @@ -121,7 +120,6 @@ volume: import traceback from ansible.module_utils.common.text.converters import to_native -from ansible_collections.community.docker.plugins.module_utils._six import iteritems from ansible_collections.community.docker.plugins.module_utils.common_api import ( AnsibleDockerClient, @@ -150,7 +148,7 @@ class TaskParameters(DockerBaseClass): self.recreate = None self.debug = None - for key, value in iteritems(client.module.params): + for key, value in client.module.params.items(): setattr(self, key, value) @@ -211,7 +209,7 @@ class DockerVolumeManager(object): parameter=self.parameters.driver_options, active=self.existing_volume.get('Options')) else: - for key, value in iteritems(self.parameters.driver_options): + for key, value in self.parameters.driver_options.items(): if (not self.existing_volume['Options'].get(key) or value != self.existing_volume['Options'][key]): differences.add('driver_options.%s' % key, diff --git a/plugins/modules/docker_volume_info.py b/plugins/modules/docker_volume_info.py index 145a10fb..ad38432c 100644 --- a/plugins/modules/docker_volume_info.py +++ b/plugins/modules/docker_volume_info.py @@ -5,8 +5,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import absolute_import, division, print_function -__metaclass__ = type +from __future__ import annotations DOCUMENTATION = r""" diff --git a/plugins/plugin_utils/common_api.py b/plugins/plugin_utils/common_api.py index eda28d48..97d2ebdb 100644 --- a/plugins/plugin_utils/common_api.py +++ b/plugins/plugin_utils/common_api.py @@ -2,8 +2,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations from ansible.errors import AnsibleConnectionFailure diff --git a/plugins/plugin_utils/socket_handler.py b/plugins/plugin_utils/socket_handler.py index e8fd266c..54d0e1e9 100644 --- a/plugins/plugin_utils/socket_handler.py +++ b/plugins/plugin_utils/socket_handler.py @@ -6,7 +6,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -from ansible_collections.community.docker.plugins.module_utils.selectors import selectors +import selectors from ansible_collections.community.docker.plugins.module_utils.socket_handler import ( DockerSocketHandlerBase, diff --git a/plugins/plugin_utils/unsafe.py b/plugins/plugin_utils/unsafe.py index 1ac2f639..a03d1e34 100644 --- a/plugins/plugin_utils/unsafe.py +++ b/plugins/plugin_utils/unsafe.py @@ -2,8 +2,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import re diff --git a/tests/sanity/ignore-2.15.txt b/tests/sanity/ignore-2.15.txt deleted file mode 100644 index ba089d07..00000000 --- a/tests/sanity/ignore-2.15.txt +++ /dev/null @@ -1,10 +0,0 @@ -.azure-pipelines/scripts/publish-codecov.py replace-urlopen -plugins/inventory/docker_containers.py yamllint:unparsable-with-libyaml -plugins/inventory/docker_machine.py yamllint:unparsable-with-libyaml -plugins/inventory/docker_swarm.py yamllint:unparsable-with-libyaml -plugins/modules/docker_container_copy_into.py validate-modules:invalid-documentation -plugins/modules/docker_container_copy_into.py validate-modules:undocumented-parameter # _max_file_size_for_diff is used by the action plugin -plugins/modules/docker_image_build.py validate-modules:invalid-documentation -plugins/module_utils/_six.py no-dict-iteritems -plugins/module_utils/_six.py pylint:ansible-bad-import-from -plugins/module_utils/_six.py pylint:deprecated-class diff --git a/tests/sanity/ignore-2.15.txt.license b/tests/sanity/ignore-2.15.txt.license deleted file mode 100644 index edff8c76..00000000 --- a/tests/sanity/ignore-2.15.txt.license +++ /dev/null @@ -1,3 +0,0 @@ -GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) -SPDX-License-Identifier: GPL-3.0-or-later -SPDX-FileCopyrightText: Ansible Project diff --git a/tests/sanity/ignore-2.16.txt b/tests/sanity/ignore-2.16.txt deleted file mode 100644 index 187e925a..00000000 --- a/tests/sanity/ignore-2.16.txt +++ /dev/null @@ -1,9 +0,0 @@ -plugins/inventory/docker_containers.py yamllint:unparsable-with-libyaml -plugins/inventory/docker_machine.py yamllint:unparsable-with-libyaml -plugins/inventory/docker_swarm.py yamllint:unparsable-with-libyaml -plugins/modules/docker_container_copy_into.py validate-modules:invalid-documentation -plugins/modules/docker_container_copy_into.py validate-modules:undocumented-parameter # _max_file_size_for_diff is used by the action plugin -plugins/modules/docker_image_build.py validate-modules:invalid-documentation -plugins/module_utils/_six.py no-dict-iteritems -plugins/module_utils/_six.py pylint:ansible-bad-import-from -plugins/module_utils/_six.py pylint:deprecated-class diff --git a/tests/sanity/ignore-2.16.txt.license b/tests/sanity/ignore-2.16.txt.license deleted file mode 100644 index edff8c76..00000000 --- a/tests/sanity/ignore-2.16.txt.license +++ /dev/null @@ -1,3 +0,0 @@ -GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) -SPDX-License-Identifier: GPL-3.0-or-later -SPDX-FileCopyrightText: Ansible Project diff --git a/tests/sanity/ignore-2.17.txt b/tests/sanity/ignore-2.17.txt index e35da816..12e0b26f 100644 --- a/tests/sanity/ignore-2.17.txt +++ b/tests/sanity/ignore-2.17.txt @@ -1,6 +1 @@ plugins/modules/docker_container_copy_into.py validate-modules:undocumented-parameter # _max_file_size_for_diff is used by the action plugin -plugins/module_utils/_api/api/client.py pylint:use-yield-from # suggested construct does not work with Python 2 -plugins/module_utils/_api/utils/build.py pylint:use-yield-from # suggested construct does not work with Python 2 -plugins/module_utils/_six.py pylint:ansible-bad-import-from -plugins/module_utils/_six.py pylint:deprecated-class -tests/unit/plugins/module_utils/test_copy.py pylint:use-yield-from # suggested construct does not work with Python 2 diff --git a/tests/sanity/ignore-2.18.txt b/tests/sanity/ignore-2.18.txt index 5ee4e327..12e0b26f 100644 --- a/tests/sanity/ignore-2.18.txt +++ b/tests/sanity/ignore-2.18.txt @@ -1,5 +1 @@ plugins/modules/docker_container_copy_into.py validate-modules:undocumented-parameter # _max_file_size_for_diff is used by the action plugin -plugins/module_utils/_api/api/client.py pylint:use-yield-from # suggested construct does not work with Python 2 -plugins/module_utils/_api/utils/build.py pylint:use-yield-from # suggested construct does not work with Python 2 -plugins/module_utils/_six.py pylint:ansible-bad-import-from -tests/unit/plugins/module_utils/test_copy.py pylint:use-yield-from # suggested construct does not work with Python 2 diff --git a/tests/sanity/ignore-2.19.txt b/tests/sanity/ignore-2.19.txt index 5ee4e327..12e0b26f 100644 --- a/tests/sanity/ignore-2.19.txt +++ b/tests/sanity/ignore-2.19.txt @@ -1,5 +1 @@ plugins/modules/docker_container_copy_into.py validate-modules:undocumented-parameter # _max_file_size_for_diff is used by the action plugin -plugins/module_utils/_api/api/client.py pylint:use-yield-from # suggested construct does not work with Python 2 -plugins/module_utils/_api/utils/build.py pylint:use-yield-from # suggested construct does not work with Python 2 -plugins/module_utils/_six.py pylint:ansible-bad-import-from -tests/unit/plugins/module_utils/test_copy.py pylint:use-yield-from # suggested construct does not work with Python 2 diff --git a/tests/sanity/ignore-2.20.txt b/tests/sanity/ignore-2.20.txt index 5ee4e327..12e0b26f 100644 --- a/tests/sanity/ignore-2.20.txt +++ b/tests/sanity/ignore-2.20.txt @@ -1,5 +1 @@ plugins/modules/docker_container_copy_into.py validate-modules:undocumented-parameter # _max_file_size_for_diff is used by the action plugin -plugins/module_utils/_api/api/client.py pylint:use-yield-from # suggested construct does not work with Python 2 -plugins/module_utils/_api/utils/build.py pylint:use-yield-from # suggested construct does not work with Python 2 -plugins/module_utils/_six.py pylint:ansible-bad-import-from -tests/unit/plugins/module_utils/test_copy.py pylint:use-yield-from # suggested construct does not work with Python 2 diff --git a/tests/unit/plugins/connection/test_docker.py b/tests/unit/plugins/connection/test_docker.py index eaa33b51..e0a2c7fc 100644 --- a/tests/unit/plugins/connection/test_docker.py +++ b/tests/unit/plugins/connection/test_docker.py @@ -2,7 +2,6 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -# Make coding more python3-ish from __future__ import (absolute_import, division, print_function) __metaclass__ = type diff --git a/tests/unit/plugins/module_utils/_api/api/test_client.py b/tests/unit/plugins/module_utils/_api/api/test_client.py index 5b39980d..8f4e9a6a 100644 --- a/tests/unit/plugins/module_utils/_api/api/test_client.py +++ b/tests/unit/plugins/module_utils/_api/api/test_client.py @@ -22,16 +22,12 @@ import tempfile import threading import time import unittest -import sys - -from ansible.module_utils import six +from http.server import BaseHTTPRequestHandler +from socketserver import ThreadingTCPServer import pytest import requests -if sys.version_info < (2, 7): - pytestmark = pytest.mark.skip('Python 2.6 is not supported') - from ansible_collections.community.docker.plugins.module_utils._api import constants, errors from ansible_collections.community.docker.plugins.module_utils._api.api.client import APIClient from ansible_collections.community.docker.tests.unit.plugins.module_utils._api.constants import DEFAULT_DOCKER_API_VERSION @@ -52,7 +48,7 @@ def response(status_code=200, content='', headers=None, reason=None, elapsed=0, request=None, raw=None): res = requests.Response() res.status_code = status_code - if not isinstance(content, six.binary_type): + if not isinstance(content, bytes): content = json.dumps(content).encode('ascii') res._content = content res.headers = requests.structures.CaseInsensitiveDict(headers or {}) @@ -103,7 +99,7 @@ def fake_delete(self, url, *args, **kwargs): def fake_read_from_socket(self, response, stream, tty=False, demux=False): - return six.binary_type() + return b"" url_base = '{prefix}/'.format(prefix=fake_api.prefix) @@ -202,13 +198,13 @@ class DockerApiTest(BaseAPIClientTest): def test_retrieve_server_version(self): client = APIClient(version="auto") - assert isinstance(client._version, six.string_types) + assert isinstance(client._version, str) assert not (client._version == "auto") client.close() def test_auto_retrieve_server_version(self): version = self.client._retrieve_server_version() - assert isinstance(version, six.string_types) + assert isinstance(version, str) def test_info(self): self.client.info() @@ -296,9 +292,7 @@ class DockerApiTest(BaseAPIClientTest): def test_stream_helper_decoding(self): status_code, content = fake_api.fake_responses[url_prefix + 'events']() - content_str = json.dumps(content) - if six.PY3: - content_str = content_str.encode('utf-8') + content_str = json.dumps(content).encode('utf-8') body = io.BytesIO(content_str) # mock a stream interface @@ -465,8 +459,7 @@ class TCPSocketStreamTest(unittest.TestCase): @classmethod def setup_class(cls): - cls.server = six.moves.socketserver.ThreadingTCPServer( - ('', 0), cls.get_handler_class()) + cls.server = ThreadingTCPServer(('', 0), cls.get_handler_class()) cls.thread = threading.Thread(target=cls.server.serve_forever) cls.thread.daemon = True cls.thread.start() @@ -484,7 +477,7 @@ class TCPSocketStreamTest(unittest.TestCase): stdout_data = cls.stdout_data stderr_data = cls.stderr_data - class Handler(six.moves.BaseHTTPServer.BaseHTTPRequestHandler, object): + class Handler(BaseHTTPRequestHandler, object): def do_POST(self): resp_data = self.get_resp_data() self.send_response(101) diff --git a/tests/unit/plugins/module_utils/_api/test_auth.py b/tests/unit/plugins/module_utils/_api/test_auth.py index b3b5a351..ce3a2c70 100644 --- a/tests/unit/plugins/module_utils/_api/test_auth.py +++ b/tests/unit/plugins/module_utils/_api/test_auth.py @@ -18,13 +18,9 @@ import random import shutil import tempfile import unittest -import sys import pytest -if sys.version_info < (2, 7): - pytestmark = pytest.mark.skip('Python 2.6 is not supported') - from ansible_collections.community.docker.plugins.module_utils._api import auth, errors from ansible_collections.community.docker.plugins.module_utils._api.credentials.errors import CredentialsNotFound from ansible_collections.community.docker.plugins.module_utils._api.credentials.store import Store diff --git a/tests/unit/plugins/module_utils/_api/test_errors.py b/tests/unit/plugins/module_utils/_api/test_errors.py index 2cc114ed..f434ca54 100644 --- a/tests/unit/plugins/module_utils/_api/test_errors.py +++ b/tests/unit/plugins/module_utils/_api/test_errors.py @@ -11,14 +11,9 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type import unittest -import sys -import pytest import requests -if sys.version_info < (2, 7): - pytestmark = pytest.mark.skip('Python 2.6 is not supported') - from ansible_collections.community.docker.plugins.module_utils._api.errors import ( APIError, DockerException, create_unexpected_kwargs_error, diff --git a/tests/unit/plugins/module_utils/_api/transport/test_sshconn.py b/tests/unit/plugins/module_utils/_api/transport/test_sshconn.py index e9189f3e..0ff7364f 100644 --- a/tests/unit/plugins/module_utils/_api/transport/test_sshconn.py +++ b/tests/unit/plugins/module_utils/_api/transport/test_sshconn.py @@ -11,12 +11,6 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type import unittest -import sys - -import pytest - -if sys.version_info < (2, 7): - pytestmark = pytest.mark.skip('Python 2.6 is not supported') from ansible_collections.community.docker.plugins.module_utils._api.transport.sshconn import SSHSocket, SSHHTTPAdapter diff --git a/tests/unit/plugins/module_utils/_api/transport/test_ssladapter.py b/tests/unit/plugins/module_utils/_api/transport/test_ssladapter.py index 77e5017e..1f00b08d 100644 --- a/tests/unit/plugins/module_utils/_api/transport/test_ssladapter.py +++ b/tests/unit/plugins/module_utils/_api/transport/test_ssladapter.py @@ -11,13 +11,9 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type import unittest -import sys import pytest -if sys.version_info < (2, 7): - pytestmark = pytest.mark.skip('Python 2.6 is not supported') - from ansible_collections.community.docker.plugins.module_utils._api.transport import ssladapter HAS_MATCH_HOSTNAME = True diff --git a/tests/unit/plugins/module_utils/_api/utils/test_build.py b/tests/unit/plugins/module_utils/_api/utils/test_build.py index 50eb703d..0686e4c2 100644 --- a/tests/unit/plugins/module_utils/_api/utils/test_build.py +++ b/tests/unit/plugins/module_utils/_api/utils/test_build.py @@ -17,13 +17,9 @@ import socket import tarfile import tempfile import unittest -import sys import pytest -if sys.version_info < (2, 7): - pytestmark = pytest.mark.skip('Python 2.6 is not supported') - from ansible_collections.community.docker.plugins.module_utils._api.constants import IS_WINDOWS_PLATFORM from ansible_collections.community.docker.plugins.module_utils._api.utils.build import exclude_paths, tar diff --git a/tests/unit/plugins/module_utils/_api/utils/test_config.py b/tests/unit/plugins/module_utils/_api/utils/test_config.py index 9448f384..0264cd9c 100644 --- a/tests/unit/plugins/module_utils/_api/utils/test_config.py +++ b/tests/unit/plugins/module_utils/_api/utils/test_config.py @@ -15,12 +15,6 @@ import unittest import shutil import tempfile import json -import sys - -import pytest - -if sys.version_info < (2, 7): - pytestmark = pytest.mark.skip('Python 2.6 is not supported') from pytest import mark, fixture diff --git a/tests/unit/plugins/module_utils/_api/utils/test_decorators.py b/tests/unit/plugins/module_utils/_api/utils/test_decorators.py index 621f2825..16e09bb6 100644 --- a/tests/unit/plugins/module_utils/_api/utils/test_decorators.py +++ b/tests/unit/plugins/module_utils/_api/utils/test_decorators.py @@ -11,12 +11,6 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type import unittest -import sys - -import pytest - -if sys.version_info < (2, 7): - pytestmark = pytest.mark.skip('Python 2.6 is not supported') from ansible_collections.community.docker.plugins.module_utils._api.api.client import APIClient from ansible_collections.community.docker.plugins.module_utils._api.utils.decorators import update_headers diff --git a/tests/unit/plugins/module_utils/_api/utils/test_json_stream.py b/tests/unit/plugins/module_utils/_api/utils/test_json_stream.py index 2d7f300f..c578ffaf 100644 --- a/tests/unit/plugins/module_utils/_api/utils/test_json_stream.py +++ b/tests/unit/plugins/module_utils/_api/utils/test_json_stream.py @@ -10,13 +10,6 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -import sys - -import pytest - -if sys.version_info < (2, 7): - pytestmark = pytest.mark.skip('Python 2.6 is not supported') - from ansible_collections.community.docker.plugins.module_utils._api.utils.json_stream import json_splitter, stream_as_text, json_stream diff --git a/tests/unit/plugins/module_utils/_api/utils/test_ports.py b/tests/unit/plugins/module_utils/_api/utils/test_ports.py index c1a08a12..b7f67927 100644 --- a/tests/unit/plugins/module_utils/_api/utils/test_ports.py +++ b/tests/unit/plugins/module_utils/_api/utils/test_ports.py @@ -11,13 +11,9 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type import unittest -import sys import pytest -if sys.version_info < (2, 7): - pytestmark = pytest.mark.skip('Python 2.6 is not supported') - from ansible_collections.community.docker.plugins.module_utils._api.utils.ports import build_port_bindings, split_port diff --git a/tests/unit/plugins/module_utils/_api/utils/test_proxy.py b/tests/unit/plugins/module_utils/_api/utils/test_proxy.py index 0eb24270..5104c870 100644 --- a/tests/unit/plugins/module_utils/_api/utils/test_proxy.py +++ b/tests/unit/plugins/module_utils/_api/utils/test_proxy.py @@ -11,12 +11,6 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type import unittest -import sys - -import pytest - -if sys.version_info < (2, 7): - pytestmark = pytest.mark.skip('Python 2.6 is not supported') from ansible_collections.community.docker.plugins.module_utils._api.utils.proxy import ProxyConfig diff --git a/tests/unit/plugins/module_utils/_api/utils/test_utils.py b/tests/unit/plugins/module_utils/_api/utils/test_utils.py index 4ba48ba2..a556a128 100644 --- a/tests/unit/plugins/module_utils/_api/utils/test_utils.py +++ b/tests/unit/plugins/module_utils/_api/utils/test_utils.py @@ -17,15 +17,9 @@ import os.path import shutil import tempfile import unittest -import sys - -from ansible_collections.community.docker.plugins.module_utils._six import PY3 import pytest -if sys.version_info < (2, 7): - pytestmark = pytest.mark.skip('Python 2.6 is not supported') - from ansible_collections.community.docker.plugins.module_utils._api.api.client import APIClient from ansible_collections.community.docker.plugins.module_utils._api.constants import IS_WINDOWS_PLATFORM from ansible_collections.community.docker.plugins.module_utils._api.errors import DockerException @@ -456,11 +450,7 @@ class UtilsTest(unittest.TestCase): def test_decode_json_header(self): obj = {'a': 'b', 'c': 1} - data = None - if PY3: - data = base64.urlsafe_b64encode(bytes(json.dumps(obj), 'utf-8')) - else: - data = base64.urlsafe_b64encode(json.dumps(obj)) + data = base64.urlsafe_b64encode(bytes(json.dumps(obj), 'utf-8')) decoded_data = decode_json_header(data) assert obj == decoded_data @@ -469,10 +459,6 @@ class SplitCommandTest(unittest.TestCase): def test_split_command_with_unicode(self): assert split_command(u'echo μμ') == ['echo', 'μμ'] - @pytest.mark.skipif(PY3, reason="shlex doesn't support bytes in py3") - def test_split_command_with_bytes(self): - assert split_command('echo μμ') == ['echo', 'μμ'] - class FormatEnvironmentTest(unittest.TestCase): def test_format_env_binary_unicode_value(self): diff --git a/tests/unit/plugins/module_utils/test_copy.py b/tests/unit/plugins/module_utils/test_copy.py index 3668573b..9a826713 100644 --- a/tests/unit/plugins/module_utils/test_copy.py +++ b/tests/unit/plugins/module_utils/test_copy.py @@ -13,8 +13,7 @@ from ansible_collections.community.docker.plugins.module_utils.copy import ( def _simple_generator(sequence): - for elt in sequence: - yield elt + yield from sequence @pytest.mark.parametrize('chunks, read_sizes', [ diff --git a/tests/unit/plugins/module_utils/test_image_archive.py b/tests/unit/plugins/module_utils/test_image_archive.py index 10573b96..76ff2006 100644 --- a/tests/unit/plugins/module_utils/test_image_archive.py +++ b/tests/unit/plugins/module_utils/test_image_archive.py @@ -62,7 +62,7 @@ def test_archived_image_manifest_raises_when_file_not_a_tar(): archived_image_manifest(__file__) raise AssertionError() except ImageArchiveInvalidException as e: - assert isinstance(e.cause, tarfile.ReadError) + assert isinstance(e.__cause__, tarfile.ReadError) assert str(__file__) in str(e) @@ -73,8 +73,8 @@ def test_archived_image_manifest_raises_when_tar_missing_manifest(tar_file_name) archived_image_manifest(tar_file_name) raise AssertionError() except ImageArchiveInvalidException as e: - assert isinstance(e.cause, KeyError) - assert 'manifest.json' in str(e.cause) + assert isinstance(e.__cause__, KeyError) + assert 'manifest.json' in str(e.__cause__) def test_archived_image_manifest_raises_when_manifest_missing_id(tar_file_name): @@ -90,5 +90,5 @@ def test_archived_image_manifest_raises_when_manifest_missing_id(tar_file_name): archived_image_manifest(tar_file_name) raise AssertionError() except ImageArchiveInvalidException as e: - assert isinstance(e.cause, KeyError) - assert 'Config' in str(e.cause) + assert isinstance(e.__cause__, KeyError) + assert 'Config' in str(e.__cause__) diff --git a/tests/unit/plugins/modules/test_docker_image.py b/tests/unit/plugins/modules/test_docker_image.py index 3401837f..b650aaa8 100644 --- a/tests/unit/plugins/modules/test_docker_image.py +++ b/tests/unit/plugins/modules/test_docker_image.py @@ -34,8 +34,7 @@ def tar_file_name(tmpdir): Return the name of a non-existing tar file in an existing temporary directory. """ - # Cast to str required by Python 2.x - return str(tmpdir.join('foo.tar')) + return tmpdir.join('foo.tar') def test_archived_image_action_when_missing(tar_file_name): diff --git a/tests/unit/plugins/plugin_utils/test_unsafe.py b/tests/unit/plugins/plugin_utils/test_unsafe.py index b2b5cdf7..c13237c8 100644 --- a/tests/unit/plugins/plugin_utils/test_unsafe.py +++ b/tests/unit/plugins/plugin_utils/test_unsafe.py @@ -3,10 +3,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -# Make coding more python3-ish -from __future__ import absolute_import, division, print_function - -__metaclass__ = type +from __future__ import annotations import pytest diff --git a/tests/unit/plugins/test_support/docker_image_archive_stubbing.py b/tests/unit/plugins/test_support/docker_image_archive_stubbing.py index 842ec4cf..3a45d0f8 100644 --- a/tests/unit/plugins/test_support/docker_image_archive_stubbing.py +++ b/tests/unit/plugins/test_support/docker_image_archive_stubbing.py @@ -37,8 +37,7 @@ def write_imitation_archive(file_name, image_id, repo_tags): def write_imitation_archive_with_manifest(file_name, manifest): - tf = tarfile.open(file_name, 'w') - try: + with tarfile.open(file_name, 'w') as tf: with TemporaryFile() as f: f.write(json.dumps(manifest).encode('utf-8')) @@ -48,10 +47,6 @@ def write_imitation_archive_with_manifest(file_name, manifest): f.seek(0) tf.addfile(ti, f) - finally: - # In Python 2.6, this does not have __exit__ - tf.close() - def write_irrelevant_tar(file_name): ''' diff --git a/tests/unit/requirements.txt b/tests/unit/requirements.txt index 386c97e2..3b01b8aa 100644 --- a/tests/unit/requirements.txt +++ b/tests/unit/requirements.txt @@ -2,8 +2,4 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -unittest2 ; python_version < '2.7' -importlib ; python_version < '2.7' - requests -backports.ssl-match-hostname ; python_version < '3.5'