diff --git a/.github/workflows/static-checks.yml b/.github/workflows/static-checks.yml index 78556ef..c434fbf 100644 --- a/.github/workflows/static-checks.yml +++ b/.github/workflows/static-checks.yml @@ -16,5 +16,7 @@ jobs: - uses: actions/checkout@v3 - name: Analysing the code with ruff run: | + set -e pip install -r test-requirements.txt ruff format --check + ruff check diff --git a/examples/hello-python/app/web.py b/examples/hello-python/app/web.py index 3008e69..6173ab7 100644 --- a/examples/hello-python/app/web.py +++ b/examples/hello-python/app/web.py @@ -1,7 +1,7 @@ # pylint: disable=import-error # pylint: disable=unused-import -import os import asyncio # noqa: F401 +import os import aioredis from aiohttp import web diff --git a/podman_compose.py b/podman_compose.py index a38b380..1ae3298 100755 --- a/podman_compose.py +++ b/podman_compose.py @@ -7,21 +7,20 @@ # https://docs.docker.com/compose/django/ # https://docs.docker.com/compose/wordpress/ # TODO: podman pod logs --color -n -f pod_testlogs -import sys -import os -import getpass import argparse -import itertools -import subprocess -import re -import hashlib -import random -import json -import glob import asyncio.subprocess -import signal - +import getpass +import glob +import hashlib +import itertools +import json +import os +import random +import re import shlex +import signal +import subprocess +import sys from asyncio import Task try: @@ -126,7 +125,8 @@ def str_to_seconds(txt): mins = int(mins) if mins else 0 sec = float(sec) if sec else 0 # "podman stop" takes only int - # Error: invalid argument "3.0" for "-t, --time" flag: strconv.ParseUint: parsing "3.0": invalid syntax + # Error: invalid argument "3.0" for "-t, --time" flag: strconv.ParseUint: parsing "3.0": + # invalid syntax return int(mins * 60.0 + sec) @@ -389,7 +389,8 @@ async def assert_volume(compose, mount_dict): is_ext = vol.get("external", None) log(f"podman volume inspect {vol_name} || podman volume create {vol_name}") # TODO: might move to using "volume list" - # podman volume list --format '{{.Name}}\t{{.MountPoint}}' -f 'label=io.podman.compose.project=HERE' + # podman volume list --format '{{.Name}}\t{{.MountPoint}}' \ + # -f 'label=io.podman.compose.project=HERE' try: _ = (await compose.podman.output([], "volume", ["inspect", vol_name])).decode("utf-8") except subprocess.CalledProcessError as e: @@ -584,7 +585,10 @@ def get_secret_args(compose, cnt, secret): # having a custom name for the external secret # has the same problem as well ext_name = declared_secret.get("name", None) - err_str = 'ERROR: Custom name/target reference "{}" for mounted external secret "{}" is not supported' + err_str = ( + 'ERROR: Custom name/target reference "{}" ' + 'for mounted external secret "{}" is not supported' + ) if ext_name and ext_name != secret_name: raise ValueError(err_str.format(secret_name, ext_name)) if target and target != secret_name: @@ -1103,7 +1107,7 @@ def flat_deps(services, with_extends=False): for c in links_ls: if ":" in c: dep_name, dep_alias = c.split(":") - if not "_aliases" in services[dep_name]: + if "_aliases" not in services[dep_name]: services[dep_name]["_aliases"] = set() services[dep_name]["_aliases"].add(dep_alias) for name, srv in services.items(): @@ -1178,9 +1182,9 @@ class Podman: async def format_out(stdout): while True: - l = await stdout.readline() - if l: - print(log_formatter, l.decode('utf-8'), end='') + line = await stdout.readline() + if line: + print(log_formatter, line.decode('utf-8'), end='') if stdout.at_eof(): break @@ -1203,14 +1207,14 @@ class Podman: try: exit_code = await p.wait() - except asyncio.CancelledError as e: - log(f"Sending termination signal") + except asyncio.CancelledError: + log("Sending termination signal") p.terminate() try: async with asyncio.timeout(10): exit_code = await p.wait() except TimeoutError: - log(f"container did not shut down after 10 seconds, killing") + log("container did not shut down after 10 seconds, killing") p.kill() exit_code = await p.wait() @@ -1530,7 +1534,8 @@ class PodmanCompose: files = args.file if not files: log( - "no compose.yaml, docker-compose.yml or container-compose.yml file found, pass files with -f" + "no compose.yaml, docker-compose.yml or container-compose.yml file found, " + "pass files with -f" ) sys.exit(-1) ex = map(os.path.exists, files) @@ -1620,7 +1625,8 @@ class PodmanCompose: if not project_name: project_name = compose.get("name", None) if project_name is None: - # More strict then actually needed for simplicity: podman requires [a-zA-Z0-9][a-zA-Z0-9_.-]* + # More strict then actually needed for simplicity: + # podman requires [a-zA-Z0-9][a-zA-Z0-9_.-]* project_name = ( self.environ.get("COMPOSE_PROJECT_NAME", None) or dir_basename.lower() ) @@ -1743,11 +1749,11 @@ class PodmanCompose: def _resolve_profiles(self, defined_services, requested_profiles=None): """ - Returns a service dictionary (key = service name, value = service config) compatible with the requested_profiles - list. + Returns a service dictionary (key = service name, value = service config) compatible with + the requested_profiles list. - The returned service dictionary contains all services which do not include/reference a profile in addition to - services that match the requested_profiles. + The returned service dictionary contains all services which do not include/reference a + profile in addition to services that match the requested_profiles. :param defined_services: The service dictionary :param requested_profiles: The profiles requested using the --profile arg. @@ -2258,8 +2264,9 @@ async def compose_up(compose: PodmanCompose, args): done, tasks = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) if args.abort_on_container_exit: if not exiting: - # If 2 containers exit at the exact same time, the cancellation of the other ones cause the status - # to overwrite. Sleeping for 1 seems to fix this and make it match docker-compose + # If 2 containers exit at the exact same time, the cancellation of the other ones + # cause the status to overwrite. Sleeping for 1 seems to fix this and make it match + # docker-compose await asyncio.sleep(1) [_.cancel() for _ in tasks if not _.cancelling() and not _.cancelled()] t: Task @@ -2729,7 +2736,8 @@ def compose_up_parse(parser): parser.add_argument( "--no-recreate", action="store_true", - help="If containers already exist, don't recreate them. Incompatible with --force-recreate and -V.", + help="If containers already exist, don't recreate them. Incompatible with --force-recreate " + "and -V.", ) parser.add_argument( "--no-build", @@ -2754,8 +2762,8 @@ def compose_up_parse(parser): "--timeout", type=int, default=None, - help="Use this timeout in seconds for container shutdown when attached or when containers are already running. \ - (default: 10)", + help="Use this timeout in seconds for container shutdown when attached or when containers " + "are already running. (default: 10)", ) parser.add_argument( "-V", @@ -2772,14 +2780,16 @@ def compose_up_parse(parser): "--scale", metavar="SERVICE=NUM", action="append", - help="Scale SERVICE to NUM instances. Overrides the `scale` setting in the Compose file if present.", + help="Scale SERVICE to NUM instances. Overrides the `scale` setting in the Compose file if " + "present.", ) parser.add_argument( "--exit-code-from", metavar="SERVICE", type=str, default=None, - help="Return the exit code of the selected service container. Implies --abort-on-container-exit.", + help="Return the exit code of the selected service container. " + "Implies --abort-on-container-exit.", ) @@ -3021,7 +3031,8 @@ def compose_build_up_parse(parser): ) parser.add_argument( "--pull-always", - help="attempt to pull a newer version of the image, Raise an error even if the image is present locally.", + help="attempt to pull a newer version of the image, Raise an error even if the image is " + "present locally.", action="store_true", ) parser.add_argument( diff --git a/pytests/test_can_merge_build.py b/pytests/test_can_merge_build.py index 86a019b..2519da7 100644 --- a/pytests/test_can_merge_build.py +++ b/pytests/test_can_merge_build.py @@ -1,12 +1,14 @@ # SPDX-License-Identifier: GPL-2.0 -import copy -import os import argparse -import yaml +import os import unittest + +import yaml from parameterized import parameterized -from podman_compose import normalize_service, PodmanCompose + +from podman_compose import PodmanCompose +from podman_compose import normalize_service class TestMergeBuild(unittest.TestCase): diff --git a/pytests/test_can_merge_cmd_ent.py b/pytests/test_can_merge_cmd_ent.py index 2a3295d..973a691 100644 --- a/pytests/test_can_merge_cmd_ent.py +++ b/pytests/test_can_merge_cmd_ent.py @@ -1,12 +1,15 @@ # SPDX-License-Identifier: GPL-2.0 +import argparse import copy import os -import argparse -import yaml import unittest + +import yaml from parameterized import parameterized -from podman_compose import normalize_service, PodmanCompose + +from podman_compose import PodmanCompose +from podman_compose import normalize_service test_keys = ["command", "entrypoint"] diff --git a/pytests/test_normalize_final_build.py b/pytests/test_normalize_final_build.py index 6915bbe..98d3ad7 100644 --- a/pytests/test_normalize_final_build.py +++ b/pytests/test_normalize_final_build.py @@ -2,16 +2,15 @@ # pylint: disable=protected-access import argparse -import copy import os -import yaml import unittest + +import yaml from parameterized import parameterized -from podman_compose import ( - normalize_final, - normalize_service_final, - PodmanCompose, -) + +from podman_compose import PodmanCompose +from podman_compose import normalize_final +from podman_compose import normalize_service_final cwd = os.path.abspath(".") diff --git a/setup.py b/setup.py index 56082e0..8f7a4e9 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 import os + from setuptools import setup try: diff --git a/tests/test_podman_compose.py b/tests/test_podman_compose.py index 999e2aa..1ad0d6e 100644 --- a/tests/test_podman_compose.py +++ b/tests/test_podman_compose.py @@ -1,8 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 -from pathlib import Path import os import unittest +from pathlib import Path + from .test_utils import RunSubprocessMixin @@ -77,8 +78,8 @@ class TestPodmanCompose(unittest.TestCase, RunSubprocessMixin): def test_extends_w_empty_service(self): """ Test that podman-compose can execute podman-compose -f up with extended File which - includes an empty service. (e.g. if the file is used as placeholder for more complex configurations.) - :return: + includes an empty service. (e.g. if the file is used as placeholder for more complex + configurations.) """ main_path = Path(__file__).parent.parent diff --git a/tests/test_podman_compose_config.py b/tests/test_podman_compose_config.py index ef383b2..e72045a 100644 --- a/tests/test_podman_compose_config.py +++ b/tests/test_podman_compose_config.py @@ -8,11 +8,13 @@ Tests the podman-compose config command which is used to return defined compose # pylint: disable=redefined-outer-name import os +import unittest + +from parameterized import parameterized + from .test_podman_compose import podman_compose_path from .test_podman_compose import test_path from .test_utils import RunSubprocessMixin -import unittest -from parameterized import parameterized def profile_compose_file(): @@ -61,8 +63,8 @@ class TestComposeConfig(unittest.TestCase, RunSubprocessMixin): """ Tests podman-compose :param profiles: The enabled profiles for the parameterized test. - :param expected_services: Dictionary used to model the expected "enabled" services in the profile. - Key = service name, Value = True if the service is enabled, otherwise False. + :param expected_services: Dictionary used to model the expected "enabled" services in the + profile. Key = service name, Value = True if the service is enabled, otherwise False. """ config_cmd = ["coverage", "run", podman_compose_path(), "-f", profile_compose_file()] config_cmd.extend(profiles) diff --git a/tests/test_podman_compose_include.py b/tests/test_podman_compose_include.py index 5ca3964..5b5044c 100644 --- a/tests/test_podman_compose_include.py +++ b/tests/test_podman_compose_include.py @@ -1,8 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 -from pathlib import Path -import subprocess import unittest +from pathlib import Path from .test_utils import RunSubprocessMixin diff --git a/tests/test_podman_compose_tests.py b/tests/test_podman_compose_tests.py index 2f4b4d9..36d56f5 100644 --- a/tests/test_podman_compose_tests.py +++ b/tests/test_podman_compose_tests.py @@ -8,7 +8,6 @@ Tests the podman compose up and down commands used to create and remove services # pylint: disable=redefined-outer-name import os -import time import unittest from .test_podman_compose import podman_compose_path @@ -51,8 +50,8 @@ class TestPodmanCompose(unittest.TestCase, RunSubprocessMixin): out, _ = self.run_subprocess_assert_returncode(run_cmd) self.assertIn(b'127.0.0.1\tlocalhost', out) - # Run it again to make sure we can run it twice. I saw an issue where a second run, with the container left up, - # would fail + # Run it again to make sure we can run it twice. I saw an issue where a second run, with + # the container left up, would fail run_cmd = [ "coverage", "run", diff --git a/tests/test_podman_compose_up_down.py b/tests/test_podman_compose_up_down.py index f7c3880..93b92fd 100644 --- a/tests/test_podman_compose_up_down.py +++ b/tests/test_podman_compose_up_down.py @@ -8,11 +8,13 @@ Tests the podman compose up and down commands used to create and remove services # pylint: disable=redefined-outer-name import os +import unittest + +from parameterized import parameterized + from .test_podman_compose import podman_compose_path from .test_podman_compose import test_path from .test_utils import RunSubprocessMixin -from parameterized import parameterized -import unittest def profile_compose_file(): @@ -23,7 +25,8 @@ def profile_compose_file(): class TestUpDown(unittest.TestCase, RunSubprocessMixin): def tearDown(self): """ - Ensures that the services within the "profile compose file" are removed between each test case. + Ensures that the services within the "profile compose file" are removed between each test + case. """ # run the test case