Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-podman for openSUSE:Factory checked in at 2023-06-03 00:06:43 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-podman (Old) and /work/SRC/openSUSE:Factory/.python-podman.new.15902 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-podman" Sat Jun 3 00:06:43 2023 rev:8 rq:1090510 version:4.5.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-podman/python-podman.changes 2022-11-01 13:42:24.779846534 +0100 +++ /work/SRC/openSUSE:Factory/.python-podman.new.15902/python-podman.changes 2023-06-03 00:06:56.257887586 +0200 @@ -1,0 +2,62 @@ +Thu Jun 1 05:35:55 UTC 2023 - Johannes Kastl <[email protected]> + +- update to 4.5.1: + * [v4.5-rhel] cherry-pick urlib3 fixes by @umohnani8 in + https://github.com/containers/podman-py/pull/274 + +------------------------------------------------------------------- +Fri Apr 28 05:09:34 UTC 2023 - Johannes Kastl <[email protected]> + +- add necessary Requires, remove outdated Requires +- add _service file + - change URL to make `osc service disabledrun download_files` + work +- update to 4.5.0: + * Change docstring to point to podman docs + * [skip-ci] Update tim-actions/get-pr-commits action to v1.2.0 + * Add renovate.json + * Fix new lint problems + * Improve exception when missing env var + * chg: Container.top to use stream_helper + * chg: Container.stats to use stream_helper + * add: stream_helper in api/parse_utils.py + * Cirrus: Update CI VM images + * Bump fixtures requirement + * Specify version verbatim in setup.cfg + * [spec] Switch license to SPDX + * podman.spec: run unit tests + * Fix version spec in setup.cfg + * Correct pyproject.toml [build-system] requires + * Fallback to pytoml on RHEL 8 and toml on 9 + * Use modern tomllib/tomli modules for reading TOML files + * Revert "Use modern tomllib/tomli modules for reading TOML + files" + * chore: Container.stats - type hints + * fix: Container.stats - invalid response for non-stream mode + * fix: Container.stats - missing stream param to requests + * Lint fix + * Merge branch 'containers:main' into + feat/container-create-secret + * Correctly add secrets to container on creation + +------------------------------------------------------------------- +Fri Feb 24 08:04:35 UTC 2023 - Dan Äermák <[email protected]> + +- cleanup requires & suggests (fixes boo#1208627) +- New upstream release 4.4.1: + This release contains necessary backports to revert the new tomli package + that was introduced but is not supported by RHEL currently. + +- New upstream release 4.4.0: + Bump version to 4.3.0 by @umohnani8 in #216 + update urllib to 1.26.5 for a CVE found in previous versions by @cdoern in #210 + Correct path for rtd conf.py by @baude in #219 + Clean up pylint configuration by @jwhonce in #222 + Use modern tomllib/tomli modules for reading TOML files by @mgorny in #214 + Added port binding range by @msisj in #224 + Update cirrus image by @rhatdan in #225 + Cirrus: Update CI VM images to F37 by @cevich in #228 + Fix the ability to run containers by @jonathanunderwood in #226 + Update files to adhere to new lint requirements by @umohnani8 in #236 + +------------------------------------------------------------------- Old: ---- podman-4.3.0.tar.gz New: ---- _service podman-4.5.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-podman.spec ++++++ --- /var/tmp/diff_new_pack.fmO5d6/_old 2023-06-03 00:06:57.205893183 +0200 +++ /var/tmp/diff_new_pack.fmO5d6/_new 2023-06-03 00:06:57.213893230 +0200 @@ -17,7 +17,6 @@ %define skip_python2 1 -%{?!python_module:%define python_module() python3-%{**}} %global flavor @BUILD_FLAVOR@%{nil} %if "%{flavor}" == "test" %define psuffix -test @@ -27,13 +26,13 @@ %bcond_with test %endif Name: python-podman%{psuffix} -Version: 4.3.0 +Version: 4.5.1 Release: 0 Summary: A library to interact with a Podman server License: Apache-2.0 Group: Development/Languages/Python URL: https://github.com/containers/podman-py -Source: https://github.com/containers/podman-py/archive/refs/tags/v%{version}.tar.gz#/podman-%{version}.tar.gz +Source: https://github.com/containers/podman-py/archive/refs/tags/v%{version}.tar.gz#./podman-%{version}.tar.gz BuildRequires: %{python_module pbr} BuildRequires: %{python_module pytoml} BuildRequires: %{python_module pyxdg} @@ -41,15 +40,9 @@ BuildRequires: %{python_module setuptools} BuildRequires: fdupes BuildRequires: python-rpm-macros -Requires: python-psutil -Requires: python-python-dateutil +Requires: python-pyxdg Requires: python-requests -Requires: python-setuptools >= 39 -Requires: python-varlink -Suggests: python-fixtures -Suggests: python-pbr -Suggests: python-pytoml -Suggests: python-pyxdg +Requires: python-urllib3 < 2.0 BuildArch: noarch %if %{with test} # SECTION test requirements @@ -62,6 +55,8 @@ BuildRequires: %{python_module setuptools >= 39} BuildRequires: %{python_module varlink} BuildRequires: %{python_module wheel} +BuildRequires: %{python_module pytest} +BuildRequires: %{python_module urllib3 < 2.0} # /SECTION %endif %python_subpackages @@ -70,7 +65,7 @@ A library to interact with a Podman server %prep -%setup -q -n podman-py-%{version} +%autosetup -n podman-py-%{version} %build %python_build @@ -83,15 +78,15 @@ %if %{with test} %check -rm -rvf podman/tests/integration -%pyunittest discover -v podman/tests/ +%{python_expand $python -m pytest podman/tests/unit} %endif %if !%{with test} %files %{python_files} %doc README.md %license LICENSE -%{python_sitelib}/* +%{python_sitelib}/podman/ +%{python_sitelib}/podman-*.egg-info/ %endif %changelog ++++++ _service ++++++ <services> <service name="download_files" mode="disabled"> </service> </services> ++++++ podman-4.3.0.tar.gz -> podman-4.5.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/.cirrus.yml new/podman-py-4.5.1/.cirrus.yml --- old/podman-py-4.3.0/.cirrus.yml 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/.cirrus.yml 2023-05-31 17:07:11.000000000 +0200 @@ -14,12 +14,11 @@ #### #### Cache-image names to test with (double-quotes around names are critical) #### - FEDORA_NAME: "fedora-36" - PRIOR_FEDORA_NAME: "fedora-35" - UBUNTU_NAME: "ubuntu-2204" + FEDORA_NAME: "fedora-37" + PRIOR_FEDORA_NAME: "fedora-36" # Google-cloud VM Images - IMAGE_SUFFIX: "c6193881921355776" + IMAGE_SUFFIX: "c20230314t204248z-f37f36d12" FEDORA_CACHE_IMAGE_NAME: "fedora-podman-py-${IMAGE_SUFFIX}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/.github/renovate.json5 new/podman-py-4.5.1/.github/renovate.json5 --- old/podman-py-4.3.0/.github/renovate.json5 1970-01-01 01:00:00.000000000 +0100 +++ new/podman-py-4.5.1/.github/renovate.json5 2023-05-31 17:07:11.000000000 +0200 @@ -0,0 +1,55 @@ +/* + Renovate is a service similar to GitHub Dependabot, but with + (fantastically) more configuration options. So many options + in fact, if you're new I recommend glossing over this cheat-sheet + prior to the official documentation: + + https://www.augmentedmind.de/2021/07/25/renovate-bot-cheat-sheet + + Configuration Update/Change Procedure: + 1. Make changes + 2. Manually validate changes (from repo-root): + + podman run -it \ + -v ./.github/renovate.json5:/usr/src/app/renovate.json5:z \ + docker.io/renovate/renovate:latest \ + renovate-config-validator + 3. Commit. + + Configuration Reference: + https://docs.renovatebot.com/configuration-options/ + + Monitoring Dashboard: + https://app.renovatebot.com/dashboard#github/containers + + Note: The Renovate bot will create/manage it's business on + branches named 'renovate/*'. Otherwise, and by + default, the only the copy of this file that matters + is the one on the `main` branch. No other branches + will be monitored or touched in any way. +*/ + +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + + /************************************************* + ****** Global/general configuration options ***** + *************************************************/ + + // Re-use predefined sets of configuration options to DRY + "extends": [ + // https://github.com/containers/automation/blob/main/renovate/defaults.json5 + "github>containers/automation//renovate/defaults.json5" + ], + + // Permit automatic rebasing when base-branch changes by more than + // one commit. + "rebaseWhen": "behind-base-branch", + + /************************************************* + *** Repository-specific configuration options *** + *************************************************/ + + // Don't leave dep. update. PRs "hanging", assign them to people. + "assignees": ["rhatdan"], +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/.github/workflows/pr.yml new/podman-py-4.5.1/.github/workflows/pr.yml --- old/podman-py-4.3.0/.github/workflows/pr.yml 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/.github/workflows/pr.yml 2023-05-31 17:07:11.000000000 +0200 @@ -10,7 +10,7 @@ steps: - name: get pr commits id: 'get-pr-commits' - uses: tim-actions/[email protected] + uses: tim-actions/[email protected] with: token: ${{ secrets.GITHUB_TOKEN }} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/.pylintrc new/podman-py-4.5.1/.pylintrc --- old/podman-py-4.3.0/.pylintrc 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/.pylintrc 2023-05-31 17:07:11.000000000 +0200 @@ -305,13 +305,6 @@ # Maximum number of lines in a module. max-module-lines=1000 -# List of optional constructs for which whitespace checking is disabled. `dict- -# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. -# `trailing-comma` allows a space between comma and closing bracket: (a, ). -# `empty-line` allows space-only lines. -no-space-check=trailing-comma, - dict-separator - # Allow the body of a class to be on the same line as the declaration if body # contains single statement. single-line-class-stmt=no @@ -329,7 +322,6 @@ # Regular expression matching correct argument names. Overrides argument- # naming-style. argument-rgx=[a-z_][a-z0-9_]{1,30}$ -argument-name-hint=[a-z_][a-z0-9_]{1,30}$ # Naming style matching correct attribute names. attr-naming-style=snake_case @@ -436,7 +428,6 @@ # Regular expression matching correct variable names. Overrides variable- # naming-style. variable-rgx=[a-z_][a-z0-9_]{2,30}$ -variable-name-hint=[a-z_][a-z0-9_]{2,30}$ [SIMILARITIES] @@ -584,6 +575,6 @@ # Exceptions that will emit a warning when being caught. Defaults to # "Exception". -overgeneral-exceptions=StandardError, - Exception, - BaseException +overgeneral-exceptions=builtins.StandardError, + builtins.Exception, + builtins.BaseException diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/.readthedocs.yaml new/podman-py-4.5.1/.readthedocs.yaml --- old/podman-py-4.3.0/.readthedocs.yaml 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/.readthedocs.yaml 2023-05-31 17:07:11.000000000 +0200 @@ -10,6 +10,6 @@ - requirements: requirements.txt sphinx: - configuration: docs/conf.py + configuration: docs/source/conf.py fail_on_warning: true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/Makefile new/podman-py-4.5.1/Makefile --- old/podman-py-4.3.0/Makefile 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/Makefile 2023-05-31 17:07:11.000000000 +0200 @@ -8,7 +8,7 @@ EPOCH_TEST_COMMIT ?= $(shell git merge-base $${DEST_BRANCH:-main} HEAD) HEAD ?= HEAD -export PODMAN_VERSION ?= "4.3.0" +export PODMAN_VERSION ?= "4.5.1" .PHONY: podman podman: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/api/__init__.py new/podman-py-4.5.1/podman/api/__init__.py --- old/podman-py-4.3.0/podman/api/__init__.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/api/__init__.py 2023-05-31 17:07:11.000000000 +0200 @@ -11,6 +11,7 @@ prepare_cidr, prepare_timestamp, stream_frames, + stream_helper, ) from podman.api.tar_utils import create_tar, prepare_containerfile, prepare_containerignore from .. import version @@ -58,4 +59,5 @@ 'prepare_filters', 'prepare_timestamp', 'stream_frames', + 'stream_helper', ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/api/parse_utils.py new/podman-py-4.5.1/podman/api/parse_utils.py --- old/podman-py-4.3.0/podman/api/parse_utils.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/api/parse_utils.py 2023-05-31 17:07:11.000000000 +0200 @@ -97,3 +97,14 @@ if not data: return yield data + + +def stream_helper( + response: Response, decode_to_json: bool = False +) -> Union[Iterator[bytes], Iterator[Dict[str, Any]]]: + """Helper to stream results and optionally decode to json""" + for value in response.iter_lines(): + if decode_to_json: + yield json.loads(value) + else: + yield value diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/api/typing_extensions.py new/podman-py-4.5.1/podman/api/typing_extensions.py --- old/podman-py-4.3.0/podman/api/typing_extensions.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/api/typing_extensions.py 2023-05-31 17:07:11.000000000 +0200 @@ -952,8 +952,7 @@ __all__.append('AsyncContextManager') elif sys.version_info[:2] >= (3, 5): - exec( - """ + exec(""" class AsyncContextManager(typing.Generic[T_co]): __slots__ = () @@ -971,8 +970,7 @@ return NotImplemented __all__.append('AsyncContextManager') -""" - ) +""") if hasattr(typing, 'DefaultDict'): DefaultDict = typing.DefaultDict @@ -1322,9 +1320,11 @@ "Some type variables (%s) are not listed in %s[%s]" % ( ", ".join(str(t) for t in tvars if t not in gvarset), - "Generic" - if any(b.__origin__ is Generic for b in bases) - else "Protocol", + ( + "Generic" + if any(b.__origin__ is Generic for b in bases) + else "Protocol" + ), ", ".join(str(g) for g in gvars), ) ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/client.py new/podman-py-4.5.1/podman/client.py --- old/podman-py-4.3.0/podman/client.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/client.py 2023-05-31 17:07:11.000000000 +0200 @@ -113,6 +113,9 @@ Returns: Client used to communicate with a Podman service. + + Raises: + ValueError when required environment variable is not set """ environment = environment or os.environ credstore_env = credstore_env or {} @@ -121,6 +124,8 @@ version = None host = environment.get("CONTAINER_HOST") or environment.get("DOCKER_HOST") or None + if host is None: + raise ValueError("CONTAINER_HOST or DOCKER_HOST must be set to URL of podman service.") return PodmanClient( base_url=host, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/domain/config.py new/podman-py-4.5.1/podman/domain/config.py --- old/podman-py-4.3.0/podman/domain/config.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/domain/config.py 2023-05-31 17:07:11.000000000 +0200 @@ -1,17 +1,24 @@ """Read containers.conf file.""" +import sys import urllib from pathlib import Path from typing import Dict, Optional import xdg.BaseDirectory -try: - import toml -except ImportError: - import pytoml as toml - from podman.api import cached_property +if sys.version_info >= (3, 11): + from tomllib import loads as toml_loads +else: + try: + from tomli import loads as toml_loads + except ImportError: + try: + from toml import loads as toml_loads + except ImportError: + from pytoml import loads as toml_loads + class ServiceConnection: """ServiceConnection defines a connection to the Podman service.""" @@ -64,7 +71,7 @@ if self.path.exists(): with self.path.open(encoding='utf-8') as file: buffer = file.read() - self.attrs = toml.loads(buffer) + self.attrs = toml_loads(buffer) def __hash__(self) -> int: return hash(tuple(self.path.name)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/domain/containers.py new/podman-py-4.5.1/podman/domain/containers.py --- old/podman-py-4.3.0/podman/domain/containers.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/domain/containers.py 2023-05-31 17:07:11.000000000 +0200 @@ -1,16 +1,13 @@ """Model and Manager for Container resources.""" -import io import json import logging import shlex from contextlib import suppress -from typing import Any, Dict, Iterable, Iterator, List, Mapping, Optional, Sequence, Tuple, Union +from typing import Any, Dict, Iterable, Iterator, List, Mapping, Optional, Tuple, Union import requests -from requests import Response from podman import api -from podman.api import Literal from podman.domain.images import Image from podman.domain.images_manager import ImagesManager from podman.domain.manager import PodmanResource @@ -391,7 +388,9 @@ ) response.raise_for_status() - def stats(self, **kwargs) -> Union[Sequence[Dict[str, bytes]], bytes]: + def stats( + self, **kwargs + ) -> Union[bytes, Dict[str, Any], Iterator[bytes], Iterator[Dict[str, Any]]]: """Return statistics for container. Keyword Args: @@ -411,27 +410,13 @@ "stream": stream, } - response = self.client.get("/containers/stats", params=params) + response = self.client.get("/containers/stats", params=params, stream=stream) response.raise_for_status() if stream: - return self._stats_helper(decode, response.iter_lines()) + return api.stream_helper(response, decode_to_json=decode) - with io.StringIO() as buffer: - for entry in response.text: - buffer.write(json.dumps(entry) + "\n") - return buffer.getvalue() - - @staticmethod - def _stats_helper( - decode: bool, body: List[Dict[str, Any]] - ) -> Iterator[Union[str, Dict[str, Any]]]: - """Helper needed to allow stats() to return either a generator or a str.""" - for entry in body: - if decode: - yield json.loads(entry) - else: - yield entry + return json.loads(response.content) if decode else response.content def stop(self, **kwargs) -> None: """Stop container. @@ -471,23 +456,20 @@ NotFound: when the container no longer exists APIError: when the service reports an error """ + stream = kwargs.get("stream", False) + params = { + "stream": stream, "ps_args": kwargs.get("ps_args"), - "stream": kwargs.get("stream", False), } - response = self.client.get(f"/containers/{self.id}/top", params=params) + response = self.client.get(f"/containers/{self.id}/top", params=params, stream=stream) response.raise_for_status() - if params["stream"]: - self._top_helper(response) + if stream: + return api.stream_helper(response, decode_to_json=True) return response.json() - @staticmethod - def _top_helper(response: Response) -> Iterator[Dict[str, Any]]: - for line in response.iter_lines(): - yield line - def unpause(self) -> None: """Unpause processes in container.""" response = self.client.post(f"/containers/{self.id}/unpause") @@ -501,7 +483,7 @@ """ raise NotImplementedError("Container.update() is not supported by Podman service.") - def wait(self, **kwargs) -> Dict[Literal["StatusCode", "Error"], Any]: + def wait(self, **kwargs) -> int: """Block until the container enters given state. Keyword Args: @@ -529,6 +511,10 @@ params["condition"] = condition if interval != "": params["interval"] = interval + + # This API endpoint responds with a JSON encoded integer. + # See: + # https://docs.podman.io/en/latest/_static/api.html#tag/containers/operation/ContainerWaitLibpod response = self.client.post(f"/containers/{self.id}/wait", params=params) response.raise_for_status() return response.json() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/domain/containers_create.py new/podman-py-4.5.1/podman/domain/containers_create.py --- old/podman-py-4.3.0/podman/domain/containers_create.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/domain/containers_create.py 2023-05-31 17:07:11.000000000 +0200 @@ -9,6 +9,7 @@ from podman.domain.containers import Container from podman.domain.images import Image from podman.domain.pods import Pod +from podman.domain.secrets import Secret from podman.errors import ImageNotFound logger = logging.getLogger("podman.containers") @@ -149,8 +150,9 @@ pids_limit (int): Tune a container's pids limit. Set -1 for unlimited. platform (str): Platform in the format os[/arch[/variant]]. Only used if the method needs to pull the requested image. - ports (Dict[str, Union[int, Tuple[str, int], List[int]]]): Ports to bind inside - the container. + ports (Dict[str, Union[int, Tuple[str, int], List[int], + Dict[str, Union[int, Tuple[str, int], List[int]]]]] + ): Ports to bind inside the container. The keys of the dictionary are the ports to bind inside the container, either as an integer or a string in the form port/protocol, where the protocol is either @@ -172,6 +174,18 @@ For example: {'9090': 7878, '10932/tcp': '8781', "8989/tcp": ("127.0.0.1", 9091)} + - A dictionary of the options mentioned above except for random host port. + The dictionary has additional option "range", + which allows binding range of ports. + + For example: + - {'2222/tcp': {"port": 3333, "range": 4}} + - {'1111/tcp': {"port": ('127.0.0.1', 1111), "range": 4}} + - {'1111/tcp': [ + {"port": 1234, "range": 4}, + {"ip": "127.0.0.1", "port": 4567} + ] + } privileged (bool): Give extended privileges to this container. publish_all_ports (bool): Publish all ports to the host. @@ -186,6 +200,7 @@ For example: {"Name": "on-failure", "MaximumRetryCount": 5} runtime (str): Runtime to use with this container. + secrets (Union[List[Secret]|List[str]]): Secrets to add to this container. security_opt (List[str]): A List[str]ing values to customize labels for MLS systems, such as SELinux. shm_size (Union[str, int]): Size of /dev/shm (e.g. 1G). @@ -210,9 +225,11 @@ the corresponding environment variables will be set in the container being built. user (Union[str, int]): Username or UID to run commands as inside the container. userns_mode (str): Sets the user namespace mode for the container when user namespace - remapping option is enabled. Supported values are: host + remapping option is enabled. Supported values documented here + https://docs.podman.io/en/latest/markdown/options/userns.container.html#userns-mode uts_mode (str): Sets the UTS namespace mode for the container. - Supported values are: host + Supported values are documented here + https://docs.podman.io/en/latest/markdown/options/uts.container.html version (str): The version of the API to use. Set to auto to automatically detect the server's version. Default: 3.0.0 volume_driver (str): The name of a volume driver/plugin. @@ -240,6 +257,9 @@ volumes_from (List[str]): List of container names or IDs to get volumes from. working_dir (str): Path to the working directory. + Returns: + A Container object. + Raises: ImageNotFound: when Image not found by Podman service APIError: when Podman service reports an error @@ -257,8 +277,9 @@ ) response.raise_for_status(not_found=ImageNotFound) - body = response.json() - return self.get(body["Id"]) + container_id = response.json()["Id"] + + return self.get(container_id) # pylint: disable=too-many-locals,too-many-statements,too-many-branches @staticmethod @@ -410,7 +431,7 @@ "sdnotifyMode": pop("sdnotifyMode"), # TODO document, podman only "seccomp_policy": pop("seccomp_policy"), # TODO document, podman only "seccomp_profile_path": pop("seccomp_profile_path"), # TODO document, podman only - "secrets": pop("secrets"), # TODO document, podman only + "secrets": [], # TODO document, podman only "selinux_opts": pop("security_opt"), "shm_size": to_bytes(pop("shm_size")), "static_mac": pop("mac_address"), @@ -488,40 +509,49 @@ pod = pod.id params["pod"] = pod # TODO document, podman only + def parse_host_port(_container_port, _protocol, _host): + result = [] + port_map = {"container_port": int(_container_port), "protocol": _protocol} + if _host is None: + result.append(port_map) + elif isinstance(_host, int) or isinstance(_host, str) and _host.isdigit(): + port_map["host_port"] = int(_host) + result.append(port_map) + elif isinstance(_host, tuple): + port_map["host_ip"] = _host[0] + port_map["host_port"] = int(_host[1]) + result.append(port_map) + elif isinstance(_host, list): + for host_list in _host: + host_list_result = parse_host_port(_container_port, _protocol, host_list) + result.extend(host_list_result) + elif isinstance(_host, dict): + _host_port = _host.get("port") + if _host_port is not None: + if ( + isinstance(_host_port, int) + or isinstance(_host_port, str) + and _host_port.isdigit() + ): + port_map["host_port"] = int(_host_port) + elif isinstance(_host_port, tuple): + port_map["host_ip"] = _host_port[0] + port_map["host_port"] = int(_host_port[1]) + if _host.get("range"): + port_map["range"] = _host.get("range") + if _host.get("ip"): + port_map["host_ip"] = _host.get("ip") + result.append(port_map) + return result + for container, host in args.pop("ports", {}).items(): if "/" in container: container_port, protocol = container.split("/") else: container_port, protocol = container, "tcp" - port_map = {"container_port": int(container_port), "protocol": protocol} - if host is None: - pass - elif isinstance(host, int) or isinstance(host, str) and host.isdigit(): - port_map["host_port"] = int(host) - elif isinstance(host, tuple): - port_map["host_ip"] = host[0] - port_map["host_port"] = int(host[1]) - elif isinstance(host, list): - for host_list in host: - port_map = {"container_port": int(container_port), "protocol": protocol} - if ( - isinstance(host_list, int) - or isinstance(host_list, str) - and host_list.isdigit() - ): - port_map["host_port"] = int(host_list) - elif isinstance(host_list, tuple): - port_map["host_ip"] = host_list[0] - port_map["host_port"] = int(host_list[1]) - else: - raise ValueError(f"'ports' value of '{host_list}' is not supported.") - params["portmappings"].append(port_map) - continue - else: - raise ValueError(f"'ports' value of '{host}' is not supported.") - - params["portmappings"].append(port_map) + port_map_list = parse_host_port(container_port, protocol, host) + params["portmappings"].extend(port_map_list) if "restart_policy" in args: params["restart_policy"] = args["restart_policy"].get("Name") @@ -576,6 +606,12 @@ volume = {"Name": key, "Dest": value["bind"], "Options": options} params["volumes"].append(volume) + for item in args.pop("secrets", []): + if isinstance(item, Secret): + params["secrets"].append({"ID": item.id}) + elif isinstance(item, str): + params["secrets"].append({"ID": item}) + if "cgroupns" in args: params["cgroupns"] = {"nsmode": args.pop("cgroupns")} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/domain/containers_manager.py new/podman-py-4.5.1/podman/domain/containers_manager.py --- old/podman-py-4.3.0/podman/domain/containers_manager.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/domain/containers_manager.py 2023-05-31 17:07:11.000000000 +0200 @@ -31,6 +31,9 @@ Args: container_id: Container name or id. + Returns: + A `Container` object corresponding to `key`. + Raises: NotFound: when Container does not exist APIError: when an error return by service diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/domain/containers_run.py new/podman-py-4.5.1/podman/domain/containers_run.py --- old/podman-py-4.3.0/podman/domain/containers_run.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/domain/containers_run.py 2023-05-31 17:07:11.000000000 +0200 @@ -77,7 +77,7 @@ if log_type in ("json-file", "journald"): log_iter = container.logs(stdout=stdout, stderr=stderr, stream=True, follow=True) - exit_status = container.wait()["StatusCode"] + exit_status = container.wait() if exit_status != 0: log_iter = None if not kwargs.get("auto_remove", False): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/domain/images_manager.py new/podman-py-4.5.1/podman/domain/images_manager.py --- old/podman-py-4.3.0/podman/domain/images_manager.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/domain/images_manager.py 2023-05-31 17:07:11.000000000 +0200 @@ -198,9 +198,7 @@ headers = { # A base64url-encoded auth configuration - "X-Registry-Auth": encode_auth_header(auth_config) - if auth_config - else "" + "X-Registry-Auth": encode_auth_header(auth_config) if auth_config else "" } params = { @@ -285,9 +283,7 @@ headers = { # A base64url-encoded auth configuration - "X-Registry-Auth": encode_auth_header(auth_config) - if auth_config - else "" + "X-Registry-Auth": encode_auth_header(auth_config) if auth_config else "" } params = { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/domain/manager.py new/podman-py-4.5.1/podman/domain/manager.py --- old/podman-py-4.3.0/podman/domain/manager.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/domain/manager.py 2023-05-31 17:07:11.000000000 +0200 @@ -118,4 +118,5 @@ # pylint: disable=not-callable return self.resource(attrs=attrs, client=self.client, collection=self) + # pylint: disable=broad-exception-raised raise Exception(f"Can't create {self.resource.__name__} from {attrs}") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/domain/networks.py new/podman-py-4.5.1/podman/domain/networks.py --- old/podman-py-4.3.0/podman/domain/networks.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/domain/networks.py 2023-05-31 17:07:11.000000000 +0200 @@ -84,26 +84,26 @@ container = container.id # TODO Talk with baude on which IPAddress field is needed... - ipam = dict( - IPv4Address=kwargs.get("ipv4_address"), - IPv6Address=kwargs.get("ipv6_address"), - Links=kwargs.get("link_local_ips"), - ) + ipam = { + "IPv4Address": kwargs.get('ipv4_address'), + "IPv6Address": kwargs.get('ipv6_address'), + "Links": kwargs.get("link_local_ips"), + } ipam = {k: v for (k, v) in ipam.items() if not (v is None or len(v) == 0)} - endpoint_config = dict( - Aliases=kwargs.get("aliases"), - DriverOpts=kwargs.get("driver_opt"), - IPAddress=kwargs.get("ipv4_address", kwargs.get("ipv6_address")), - IPAMConfig=ipam, - Links=kwargs.get("link_local_ips"), - NetworkID=self.id, - ) + endpoint_config = { + "Aliases": kwargs.get("aliases"), + "DriverOpts": kwargs.get("driver_opt"), + "IPAddress": kwargs.get("ipv4_address", kwargs.get("ipv6_address")), + "IPAMConfig": ipam, + "Links": kwargs.get("link_local_ips"), + "NetworkID": self.id, + } endpoint_config = { k: v for (k, v) in endpoint_config.items() if not (v is None or len(v) == 0) } - data = dict(Container=container, EndpointConfig=endpoint_config) + data = {"Container": container, "EndpointConfig": endpoint_config} data = {k: v for (k, v) in data.items() if not (v is None or len(v) == 0)} response = self.client.post( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/domain/secrets.py new/podman-py-4.5.1/podman/domain/secrets.py --- old/podman-py-4.3.0/podman/domain/secrets.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/domain/secrets.py 2023-05-31 17:07:11.000000000 +0200 @@ -72,7 +72,7 @@ """ response = self.client.get(f"/secrets/{secret_id}/json") response.raise_for_status() - return self.prepare_model(attrs=(response.json())) + return self.prepare_model(attrs=response.json()) def list(self, **kwargs) -> List[Secret]: """Report on Secrets. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/domain/volumes.py new/podman-py-4.5.1/podman/domain/volumes.py --- old/podman-py-4.3.0/podman/domain/volumes.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/domain/volumes.py 2023-05-31 17:07:11.000000000 +0200 @@ -70,7 +70,7 @@ headers={"Content-Type": "application/json"}, ) response.raise_for_status() - return self.prepare_model(attrs=(response.json())) + return self.prepare_model(attrs=response.json()) def exists(self, key: str) -> bool: response = self.client.get(f"/volumes/{key}/exists") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/tests/__init__.py new/podman-py-4.5.1/podman/tests/__init__.py --- old/podman-py-4.3.0/podman/tests/__init__.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/tests/__init__.py 2023-05-31 17:07:11.000000000 +0200 @@ -3,5 +3,5 @@ # Do not auto-update these from version.py, # as test code should be changed to reflect changes in Podman API versions BASE_SOCK = "unix:///run/api.sock" -LIBPOD_URL = "http://%2Frun%2Fapi.sock/v4.3.0/libpod" +LIBPOD_URL = "http://%2Frun%2Fapi.sock/v4.5.1/libpod" COMPATIBLE_URL = "http://%2Frun%2Fapi.sock/v1.40" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/tests/integration/test_container_create.py new/podman-py-4.5.1/podman/tests/integration/test_container_create.py --- old/podman-py-4.3.0/podman/tests/integration/test_container_create.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/tests/integration/test_container_create.py 2023-05-31 17:07:11.000000000 +0200 @@ -100,56 +100,69 @@ def test_container_ports(self): """Test ports binding""" - port_tests = { - '97/tcp': '43', - '2/udp': ('127.0.0.1', '939'), - '11123/tcp': [[('127.0.0.1', '11123'), ('127.0.0.1', '112')], ['1123', '159']], - } - for container_port, host_port in port_tests.items(): - if isinstance(host_port, str) or isinstance(host_port, tuple): - self._test_container_ports(container_port, host_port) - else: - for port_option in host_port: - self._test_container_ports(container_port, port_option) - - def _test_container_ports(self, container_port, host_port): - """ "Base for tests to check port binding is configured correctly""" - - def __get_expected_value(container_p, host_p): - """Generate the expected value based on the input""" - if isinstance(host_p, str): - return {container_p: [{'HostIp': '', 'HostPort': host_p}]} - elif isinstance(host_p, tuple): - return {container_p: [{'HostIp': host_p[0], 'HostPort': host_p[1]}]} - else: - host_ports = [] - for host_port in host_p: - if isinstance(host_port, tuple): - host_ports.append({'HostIp': host_port[0], 'HostPort': host_port[1]}) - elif isinstance(host_port, str): - host_ports.append({'HostIp': '', 'HostPort': host_port}) - return {container_p: host_ports} - - expected_value = __get_expected_value(container_port, host_port) - container = self.client.containers.create( - self.alpine_image, ports={container_port: host_port} - ) - self.containers.append(container) - - self.assertTrue( - all( - [ - x in expected_value - for x in container.attrs.get('HostConfig', dict()).get('PortBindings') - ] + port_tests = [ + { + 'input': {'97/tcp': '43'}, + 'expected_output': {'97/tcp': [{'HostIp': '', 'HostPort': '43'}]}, + }, + { + 'input': {'2/udp': ('127.0.0.1', '939')}, + 'expected_output': {'2/udp': [{'HostIp': '127.0.0.1', 'HostPort': '939'}]}, + }, + { + 'input': { + '11123/tcp': [('127.0.0.1', '11123'), ('127.0.0.1', '112'), '1123', '159'] + }, + 'expected_output': { + '11123/tcp': [ + {'HostIp': '127.0.0.1', 'HostPort': '11123'}, + {'HostIp': '', 'HostPort': '112'}, + {'HostIp': '', 'HostPort': '1123'}, + {'HostIp': '', 'HostPort': '159'}, + ] + }, + }, + { + 'input': {'1111/tcp': {"port": ('127.0.0.1', 1111), "range": 3}}, + 'expected_output': { + '1111/tcp': [{'HostIp': '127.0.0.1', 'HostPort': '1111'}], + '1112/tcp': [{'HostIp': '127.0.0.1', 'HostPort': '1112'}], + '1113/tcp': [{'HostIp': '127.0.0.1', 'HostPort': '1113'}], + }, + }, + { + 'input': { + '1222/tcp': [{"port": 1234, "range": 2}, {"ip": "127.0.0.1", "port": 4567}] + }, + 'expected_output': { + '1222/tcp': [ + {'HostIp': '', 'HostPort': '1234'}, + {'HostIp': '127.0.0.1', 'HostPort': '4567'}, + ], + '1223/tcp': [{'HostIp': '', 'HostPort': '1235'}], + }, + }, + ] + + for port_test in port_tests: + container = self.client.containers.create(self.alpine_image, ports=port_test['input']) + self.containers.append(container) + + self.assertTrue( + all( + [ + x in port_test['expected_output'] + for x in container.attrs.get('HostConfig', {}).get('PortBindings') + ] + ) ) - ) - def test_container_healtchecks(self): + def test_container_healthchecks(self): """Test passing various healthcheck options""" - parameters = {} - parameters['healthcheck'] = {'Test': ['CMD-SHELL curl http://localhost || exit']} - parameters['health_check_on_failure_action'] = 1 + parameters = { + 'healthcheck': {'Test': ['CMD-SHELL curl http://localhost || exit']}, + 'health_check_on_failure_action': 1, + } container = self.client.containers.create(self.alpine_image, **parameters) self.containers.append(container) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/tests/integration/test_containers.py new/podman-py-4.5.1/podman/tests/integration/test_containers.py --- old/podman-py-4.3.0/podman/tests/integration/test_containers.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/tests/integration/test_containers.py 2023-05-31 17:07:11.000000000 +0200 @@ -141,7 +141,8 @@ self.assertIn(top_ctnr.id, report["ContainersDeleted"]) # SpaceReclaimed is the size of the content created during the running of the container - self.assertEqual(report["SpaceReclaimed"], 0) + # TODO: This should probably check if the podman version is >= 4.6 (guess) + self.assertGreater(report["SpaceReclaimed"], 0) with self.assertRaises(NotFound): self.client.containers.get(top_ctnr.id) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/tests/integration/test_images.py new/podman-py-4.5.1/podman/tests/integration/test_images.py --- old/podman-py-4.3.0/podman/tests/integration/test_images.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/tests/integration/test_images.py 2023-05-31 17:07:11.000000000 +0200 @@ -121,10 +121,7 @@ self.assertIn("payload does not match", e.exception.explanation) def test_build(self): - buffer = io.StringIO( - f"""FROM quay.io/libpod/alpine_labels:latest -""" - ) + buffer = io.StringIO(f"""FROM quay.io/libpod/alpine_labels:latest""") image, stream = self.client.images.build(fileobj=buffer) self.assertIsNotNone(image) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/tests/integration/test_system.py new/podman-py-4.5.1/podman/tests/integration/test_system.py --- old/podman-py-4.3.0/podman/tests/integration/test_system.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/tests/integration/test_system.py 2023-05-31 17:07:11.000000000 +0200 @@ -57,3 +57,9 @@ ) ) self.assertIn("lookup fake_registry: no such host", e.exception.explanation) + + def test_from_env(self): + """integration: from_env() error message""" + with self.assertRaises(ValueError) as e: + next(self.client.from_env()) + self.assertIn("CONTAINER_HOST or DOCKER_HOST", repr(e.exception)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/tests/unit/test_config.py new/podman-py-4.5.1/podman/tests/unit/test_config.py --- old/podman-py-4.3.0/podman/tests/unit/test_config.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/tests/unit/test_config.py 2023-05-31 17:07:11.000000000 +0200 @@ -8,8 +8,7 @@ class PodmanConfigTestCase(unittest.TestCase): - opener = mock.mock_open( - read_data=""" + opener = mock.mock_open(read_data=""" [containers] log_size_max = -1 pids_limit = 2048 @@ -28,8 +27,7 @@ identity = "/home/qe/.ssh/id_rsa" [network] -""" - ) +""") def setUp(self) -> None: super().setUp() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/tests/unit/test_container.py new/podman-py-4.5.1/podman/tests/unit/test_container.py --- old/podman-py-4.3.0/podman/tests/unit/test_container.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/tests/unit/test_container.py 2023-05-31 17:07:11.000000000 +0200 @@ -411,6 +411,53 @@ self.assertDictEqual(actual, body) self.assertTrue(adapter.called_once) + @requests_mock.Mocker() + def test_top_with_streaming(self, mock): + stream = [ + { + "Processes": [ + [ + 'jhonce', + '2417', + '2274', + '0', + 'Mar01', + '?', + '00:00:01', + ( + '/usr/bin/ssh-agent /bin/sh -c exec -l /bin/bash -c' + ' "/usr/bin/gnome-session"' + ), + ], + ['jhonce', '5544', '3522', '0', 'Mar01', 'pts/1', '00:00:02', '-bash'], + ['jhonce', '6140', '3522', '0', 'Mar01', 'pts/2', '00:00:00', '-bash'], + ], + "Titles": ["UID", "PID", "PPID", "C", "STIME", "TTY", "TIME CMD"], + } + ] + + buffer = io.StringIO() + for entry in stream: + buffer.write(json.JSONEncoder().encode(entry)) + buffer.write("\n") + + adapter = mock.get( + tests.LIBPOD_URL + + "/containers/87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/top" + "?stream=True", + text=buffer.getvalue(), + ) + + container = Container(attrs=FIRST_CONTAINER, client=self.client.api) + top_stats = container.top(stream=True) + + self.assertIsInstance(top_stats, Iterable) + for response, actual in zip(top_stats, stream): + self.assertIsInstance(response, dict) + self.assertDictEqual(response, actual) + + self.assertTrue(adapter.called_once) + if __name__ == '__main__': unittest.main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/tests/unit/test_containersmanager.py new/podman-py-4.5.1/podman/tests/unit/test_containersmanager.py --- old/podman-py-4.3.0/podman/tests/unit/test_containersmanager.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/tests/unit/test_containersmanager.py 2023-05-31 17:07:11.000000000 +0200 @@ -6,14 +6,15 @@ except: # Python < 3.10 from collections import Iterator -from unittest.mock import patch, DEFAULT + +from unittest.mock import DEFAULT, patch import requests_mock from podman import PodmanClient, tests from podman.domain.containers import Container from podman.domain.containers_manager import ContainersManager -from podman.errors import NotFound, ImageNotFound +from podman.errors import ImageNotFound, NotFound FIRST_CONTAINER = { "Id": "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd", @@ -276,7 +277,7 @@ ) with patch.multiple(Container, logs=DEFAULT, wait=DEFAULT, autospec=True) as mock_container: - mock_container["wait"].return_value = {"StatusCode": 0} + mock_container["wait"].return_value = 0 with self.subTest("Results not streamed"): mock_container["logs"].return_value = iter(mock_logs) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/tests/unit/test_parse_utils.py new/podman-py-4.5.1/podman/tests/unit/test_parse_utils.py --- old/podman-py-4.3.0/podman/tests/unit/test_parse_utils.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/tests/unit/test_parse_utils.py 2023-05-31 17:07:11.000000000 +0200 @@ -1,9 +1,12 @@ import datetime import ipaddress +import json import unittest -from typing import Any, Optional - from dataclasses import dataclass +from typing import Any, Iterable, Optional, Tuple +from unittest import mock + +from requests import Response from podman import api @@ -14,7 +17,7 @@ class TestCase: name: str input: Any - expected: Optional[str] + expected: Tuple[str, Optional[str]] cases = [ TestCase(name="empty str", input="", expected=("", None)), @@ -56,12 +59,36 @@ self.assertEqual(api.prepare_timestamp(None), None) with self.assertRaises(ValueError): - api.prepare_timestamp("bad input") + api.prepare_timestamp("bad input") # type: ignore def test_prepare_cidr(self): net = ipaddress.IPv4Network("127.0.0.0/24") self.assertEqual(api.prepare_cidr(net), ("127.0.0.0", "////AA==")) + def test_stream_helper(self): + streamed_results = [b'{"test":"val1"}', b'{"test":"val2"}'] + mock_response = mock.Mock(spec=Response) + mock_response.iter_lines.return_value = iter(streamed_results) + + streamable = api.stream_helper(mock_response) + + self.assertIsInstance(streamable, Iterable) + for expected, actual in zip(streamed_results, streamable): + self.assertIsInstance(actual, bytes) + self.assertEqual(expected, actual) + + def test_stream_helper_with_decode(self): + streamed_results = [b'{"test":"val1"}', b'{"test":"val2"}'] + mock_response = mock.Mock(spec=Response) + mock_response.iter_lines.return_value = iter(streamed_results) + + streamable = api.stream_helper(mock_response, decode_to_json=True) + + self.assertIsInstance(streamable, Iterable) + for expected, actual in zip(streamed_results, streamable): + self.assertIsInstance(actual, dict) + self.assertDictEqual(json.loads(expected), actual) + if __name__ == '__main__': unittest.main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/tests/unit/test_podmanclient.py new/podman-py-4.5.1/podman/tests/unit/test_podmanclient.py --- old/podman-py-4.3.0/podman/tests/unit/test_podmanclient.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/tests/unit/test_podmanclient.py 2023-05-31 17:07:11.000000000 +0200 @@ -13,8 +13,7 @@ class PodmanClientTestCase(unittest.TestCase): """Test the PodmanClient() object.""" - opener = mock.mock_open( - read_data=""" + opener = mock.mock_open(read_data=""" [containers] log_size_max = -1 pids_limit = 2048 @@ -33,8 +32,7 @@ identity = "/home/qe/.ssh/id_rsa" [network] -""" - ) +""") def setUp(self) -> None: super().setUp() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/podman/version.py new/podman-py-4.5.1/podman/version.py --- old/podman-py-4.3.0/podman/version.py 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/podman/version.py 2023-05-31 17:07:11.000000000 +0200 @@ -1,4 +1,4 @@ """Version of PodmanPy.""" -__version__ = "4.3.0" +__version__ = "4.5.1" __compatible_version__ = "1.40" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/pyproject.toml new/podman-py-4.5.1/pyproject.toml --- old/podman-py-4.3.0/pyproject.toml 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/pyproject.toml 2023-05-31 17:07:11.000000000 +0200 @@ -9,6 +9,7 @@ \.git | \.tox | \.venv + | \.history | build | dist | docs @@ -21,13 +22,7 @@ [build-system] # Any changes should be copied into requirements.txt, setup.cfg, and/or test-requirements.txt requires = [ - "pyxdg>=0.26", - "requests>=2.24", "setuptools>=46.4", - "sphinx", - "toml>=0.10.2", - "urllib3>=1.24.2", - "wheel", ] build-backend = "setuptools.build_meta" [tool.pytest.ini_options] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/python-podman.spec.rpkg new/podman-py-4.5.1/python-podman.spec.rpkg --- old/podman-py-4.3.0/python-podman.spec.rpkg 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/python-podman.spec.rpkg 2023-05-31 17:07:11.000000000 +0200 @@ -11,6 +11,12 @@ %global old_rhel 0 %endif +%if %{undefined rhel} +%bcond_without tests +%else +%bcond_with tests +%endif + %global pypi_name podman %global desc %{pypi_name} is a library of bindings to use the RESTful API for Podman. @@ -28,8 +34,7 @@ # Basic description of the package Summary: Manage Pods, Containers and Container Images -# License. We assume GPLv2+ here. -License: ASL 2.0 +License: Apache-2.0 # Home page of the project. Can also point to the public Git repository page. URL: https://github.com/containers/podman-py @@ -49,20 +54,16 @@ BuildRequires: git-core BuildRequires: python%{python3_pkgversion}-devel %if %{?old_rhel} -BuildRequires: python%{python3_pkgversion}-pytoml BuildRequires: python%{python3_pkgversion}-pyxdg BuildRequires: python%{python3_pkgversion}-requests BuildRequires: python%{python3_pkgversion}-setuptools -Requires: python%{python3_pkgversion}-pytoml +BuildRequires: python%{python3_pkgversion}-pytoml Requires: python%{python3_pkgversion}-pyxdg Requires: python%{python3_pkgversion}-requests +Requires: python%{python3_pkgversion}-pytoml %else BuildRequires: pyproject-rpm-macros %endif -%if 0%{?fedora} <= 35 && ! 0%{?rhel} -BuildRequires: python%{python3_pkgversion}-toml -Requires: python%{python3_pkgversion}-toml -%endif Provides: %{pypi_name}-py = %{version}-%{release} Summary: %{summary} %{?python_provide:%python_provide python%{python3_pkgversion}-%{pypi_name}} @@ -75,6 +76,23 @@ %prep {{{ git_dir_setup_macro }}} +%if %{defined el8} +# RHEL 8 does not have tomli. Use pytoml instead. +sed -i 's|tomli.*|pytoml|' setup.cfg +# Ensure patch was properly applied. +(! grep 'tomli' setup.cfg) +%endif + +%if %{defined el9} +# RHEL 9 does not have tomli. Use toml instead. +sed -i 's|tomli.*|toml|' setup.cfg +# Ensure patch was properly applied. +(! grep 'tomli' setup.cfg) +%endif + +# Remove lint and integration test dependencies +sed -i -E '/black|coverage|pylint|fixtures/d' test-requirements.txt + %if ! %{?old_rhel} %generate_buildrequires %pyproject_buildrequires %{?with_tests:-t} @@ -95,6 +113,11 @@ %pyproject_install %endif +%check +%if %{with tests} +%tox -- -- podman/tests/unit +%endif + # This lists all the files that are included in the rpm package and that # are going to be installed into target system where the rpm is installed. %files -n python3-podman diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/requirements.txt new/podman-py-4.5.1/requirements.txt --- old/podman-py-4.3.0/requirements.txt 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/requirements.txt 2023-05-31 17:07:11.000000000 +0200 @@ -3,6 +3,6 @@ requests>=2.24 setuptools sphinx -toml>=0.10.2 -urllib3>=1.24.2 +tomli>=1.2.3; python_version<'3.11' +urllib3>=1.26.5,<2.0.0 wheel diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/setup.cfg new/podman-py-4.5.1/setup.cfg --- old/podman-py-4.3.0/setup.cfg 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/setup.cfg 2023-05-31 17:07:11.000000000 +0200 @@ -1,6 +1,6 @@ [metadata] name = podman -version = attr: podman.__version__ +version = 4.5.1 author = Brent Baude, Jhon Honce author_email = [email protected] description = Bindings for Podman RESTful API @@ -8,7 +8,7 @@ long_description_content_type = text/markdown url = https://github.com/containers/podman-py license = Apache-2.0 -license_file = LICENSE +license_files = LICENSE platforms = any project_urls = Bug Tracker = https://github.com/containers/podman-py/issues @@ -34,10 +34,10 @@ test_suite = # Any changes should be copied into pyproject.toml install_requires = - pyxdg>=0.26 - requests>=2.24 - toml>=0.10.2 - urllib3>=1.24.2 + pyxdg >=0.26 + requests >=2.24 + tomli>=1.2.3; python_version<'3.11' + urllib3 >= 1.26.5, < 2.0.0 # typing_extensions are included for RHEL 8.5 # typing_extensions;python_version<'3.8' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/test-requirements.txt new/podman-py-4.5.1/test-requirements.txt --- old/podman-py-4.3.0/test-requirements.txt 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/test-requirements.txt 2023-05-31 17:07:11.000000000 +0200 @@ -2,7 +2,7 @@ -r requirements.txt black coverage -fixtures~=3.0.0 +fixtures~=4.0.0 pylint pytest requests-mock diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podman-py-4.3.0/tox.ini new/podman-py-4.5.1/tox.ini --- old/podman-py-4.3.0/tox.ini 2022-10-19 23:32:04.000000000 +0200 +++ new/podman-py-4.5.1/tox.ini 2023-05-31 17:07:11.000000000 +0200 @@ -18,6 +18,8 @@ commands = {posargs} [testenv:pylint] +depends = py310 +basepython = python3.10 allowlist_externals = pylint commands = pylint podman
