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 2022-08-16 17:07:51
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-podman (Old)
 and      /work/SRC/openSUSE:Factory/.python-podman.new.1521 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-podman"

Tue Aug 16 17:07:51 2022 rev:6 rq:995862 version:4.2.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-podman/python-podman.changes      
2022-07-04 11:32:45.992012650 +0200
+++ /work/SRC/openSUSE:Factory/.python-podman.new.1521/python-podman.changes    
2022-08-16 17:07:52.755902422 +0200
@@ -1,0 +2,10 @@
+Mon Aug 15 11:45:24 UTC 2022 - Michael Str??der <mich...@stroeder.com>
+
+- update to 4.2.0
+  * Added support for devices in container creation
+  * Implemented the login endpoint
+  * Added relabel option for mounts and other mount option support
+  * Implemented exec_run
+  * Bug Fixes
+
+-------------------------------------------------------------------

Old:
----
  podman-4.0.0.tar.gz

New:
----
  podman-4.2.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-podman.spec ++++++
--- /var/tmp/diff_new_pack.Y8mWtR/_old  2022-08-16 17:07:53.271903965 +0200
+++ /var/tmp/diff_new_pack.Y8mWtR/_new  2022-08-16 17:07:53.279903989 +0200
@@ -27,7 +27,7 @@
 %bcond_with test
 %endif
 Name:           python-podman%{psuffix}
-Version:        4.0.0
+Version:        4.2.0
 Release:        0
 Summary:        A library to interact with a Podman server
 License:        Apache-2.0

++++++ podman-4.0.0.tar.gz -> podman-4.2.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-4.0.0/.cirrus.yml 
new/podman-py-4.2.0/.cirrus.yml
--- old/podman-py-4.0.0/.cirrus.yml     2022-02-28 17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/.cirrus.yml     2022-08-10 15:03:52.000000000 +0200
@@ -14,12 +14,12 @@
     ####
     #### Cache-image names to test with (double-quotes around names are 
critical)
     ####
-    FEDORA_NAME: "fedora-35"
-    PRIOR_FEDORA_NAME: "fedora-34"
-    UBUNTU_NAME: "ubuntu-2110"
+    FEDORA_NAME: "fedora-36"
+    PRIOR_FEDORA_NAME: "fedora-35"
+    UBUNTU_NAME: "ubuntu-2204"
 
     # Google-cloud VM Images
-    IMAGE_SUFFIX: "c4764556961513472"
+    IMAGE_SUFFIX: "c6193881921355776"
     FEDORA_CACHE_IMAGE_NAME: "fedora-podman-py-${IMAGE_SUFFIX}"
 
 
@@ -90,7 +90,7 @@
     name: "VM img. keepalive"
 
     container: &smallcontainer
-        image: "quay.io/libpod/imgts:$IMAGE_SUFFIX"
+        image: "quay.io/libpod/imgts:latest"
         cpu: 1
         memory: 1
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-4.0.0/CONTRIBUTING.md 
new/podman-py-4.2.0/CONTRIBUTING.md
--- old/podman-py-4.0.0/CONTRIBUTING.md 2022-02-28 17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/CONTRIBUTING.md 2022-08-10 15:03:52.000000000 +0200
@@ -70,11 +70,15 @@
   `tox -e black-format` to update the code formatting prior to committing.
 - Pass pylint
   - exceptions are possible, but you will need to make a good argument
-- use spaces not tabs for indentation
+- Use spaces not tabs for indentation
 - This is open source software. Consider the people who will read your code,
   and make it look nice for them. It's sort of like driving a car: Perhaps
   you love doing donuts when you're alone, but with passengers the goal is to
   make the ride as smooth as possible.
+- Use Google style python 
[docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
+    - A general exception is made for kwargs where we use the Sphinx extension 
of adding a section
+      "Keyword Arguments" and documenting the accepted keyword arguments, 
their type and usage.
+      Example: kwarg1 (int): Description of kwarg1
 
 Again thank you for your interest and participation.
 Jhon Honce `<jhonce at redhat dot com>`
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-4.0.0/Makefile new/podman-py-4.2.0/Makefile
--- old/podman-py-4.0.0/Makefile        2022-02-28 17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/Makefile        2022-08-10 15:03:52.000000000 +0200
@@ -8,7 +8,7 @@
 EPOCH_TEST_COMMIT ?= $(shell git merge-base $${DEST_BRANCH:-main} HEAD)
 HEAD ?= HEAD
 
-export PODMAN_VERSION ?= "4.0.0"
+export PODMAN_VERSION ?= "4.2.0"
 
 .PHONY: podman
 podman:
@@ -24,7 +24,7 @@
 .PHONY: tests
 tests: tox
        # see tox.ini for environment variable settings
-       $(PYTHON) -m tox -e pylint,coverage,py36,py38,py39,py310
+       $(PYTHON) -m tox -e pylint,coverage,py36,py38,py39,py310,py311
 
 .PHONY: unittest
 unittest:
@@ -63,6 +63,10 @@
                podman podman/tests
        sphinx-build build/docs/source build/html
 
+.PHONY: rpm
+rpm: ## Build rpm packages
+       rpkg local
+
 # .PHONY: install
 HEAD ?= HEAD
 # install:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-4.0.0/OWNERS new/podman-py-4.2.0/OWNERS
--- old/podman-py-4.0.0/OWNERS  2022-02-28 17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/OWNERS  2022-08-10 15:03:52.000000000 +0200
@@ -1,8 +1,10 @@
 approvers:
   - baude
+  - cdoern
   - edsantiago
   - giuseppe
   - jwhonce
+  - lsm5
   - Luap99
   - mheon
   - mwhahaha
@@ -13,9 +15,11 @@
 reviewers:
   - ashley-cui
   - baude
+  - cdoern
   - edsantiago
   - giuseppe
   - jwhonce
+  - lsm5
   - Luap99
   - mheon
   - mwhahaha
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-4.0.0/podman/api/client.py 
new/podman-py-4.2.0/podman/api/client.py
--- old/podman-py-4.0.0/podman/api/client.py    2022-02-28 17:35:01.000000000 
+0100
+++ new/podman-py-4.2.0/podman/api/client.py    2022-08-10 15:03:52.000000000 
+0200
@@ -1,7 +1,7 @@
 """APIClient for connecting to Podman service."""
 import json
 import urllib.parse
-from typing import IO, Any, ClassVar, Iterable, List, Mapping, Optional, 
Tuple, Union, Type
+from typing import Any, ClassVar, IO, Iterable, List, Mapping, Optional, 
Tuple, Type, Union
 
 import requests
 from requests.adapters import HTTPAdapter
@@ -46,9 +46,7 @@
         """Forward any query for an attribute not defined in this proxy class 
to wrapped class."""
         return getattr(self._response, item)
 
-    def raise_for_status(
-        self, not_found: Type[APIError] = NotFound
-    ) -> None:  # pylint: disable=arguments-differ
+    def raise_for_status(self, not_found: Type[APIError] = NotFound) -> None:
         """Raises exception when Podman service reports one."""
         if self.status_code < 400:
             return
@@ -69,8 +67,7 @@
     """Client for Podman service API."""
 
     # Abstract methods (delete,get,head,post) are specialized and pylint 
cannot walk hierarchy.
-    # pylint: disable=arguments-differ
-    # pylint: disable=too-many-instance-attributes
+    # pylint: 
disable=too-many-instance-attributes,arguments-differ,arguments-renamed
 
     supported_schemes: ClassVar[List[str]] = (
         "unix",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-4.0.0/podman/api/http_utils.py 
new/podman-py-4.2.0/podman/api/http_utils.py
--- old/podman-py-4.0.0/podman/api/http_utils.py        2022-02-28 
17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/podman/api/http_utils.py        2022-08-10 
15:03:52.000000000 +0200
@@ -1,4 +1,5 @@
 """Utility functions for working with URLs."""
+import base64
 import collections.abc
 import json
 from typing import Dict, List, Mapping, Optional, Union, Any
@@ -88,3 +89,7 @@
             canonical[key] = proposal
 
     return canonical
+
+
+def encode_auth_header(auth_config: Dict[str, str]) -> str:
+    return base64.b64encode(json.dumps(auth_config).encode('utf-8'))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-4.0.0/podman/api/typing_extensions.py 
new/podman-py-4.2.0/podman/api/typing_extensions.py
--- old/podman-py-4.0.0/podman/api/typing_extensions.py 2022-02-28 
17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/podman/api/typing_extensions.py 2022-08-10 
15:03:52.000000000 +0200
@@ -984,7 +984,6 @@
         metaclass=_ExtensionsGenericMeta,
         extra=collections.defaultdict,
     ):
-
         __slots__ = ()
 
         def __new__(cls, *args, **kwds):
@@ -1000,7 +999,6 @@
         metaclass=_ExtensionsGenericMeta,
         extra=collections.defaultdict,
     ):
-
         __slots__ = ()
 
         def __new__(cls, *args, **kwds):
@@ -1021,7 +1019,6 @@
         metaclass=_ExtensionsGenericMeta,
         extra=collections.OrderedDict,
     ):
-
         __slots__ = ()
 
         def __new__(cls, *args, **kwds):
@@ -1037,7 +1034,6 @@
         metaclass=_ExtensionsGenericMeta,
         extra=collections.OrderedDict,
     ):
-
         __slots__ = ()
 
         def __new__(cls, *args, **kwds):
@@ -1061,7 +1057,6 @@
     class Counter(
         collections.Counter, typing.Dict[T, int], metaclass=_CounterMeta, 
extra=collections.Counter
     ):
-
         __slots__ = ()
 
         def __new__(cls, *args, **kwds):
@@ -1077,7 +1072,6 @@
         metaclass=_ExtensionsGenericMeta,
         extra=collections.Counter,
     ):
-
         __slots__ = ()
 
         def __new__(cls, *args, **kwds):
@@ -1093,7 +1087,6 @@
         metaclass=_ExtensionsGenericMeta,
         extra=collections.Counter,
     ):
-
         __slots__ = ()
 
         def __new__(cls, *args, **kwds):
@@ -1115,7 +1108,6 @@
             metaclass=_ExtensionsGenericMeta,
             extra=collections.ChainMap,
         ):
-
             __slots__ = ()
 
             def __new__(cls, *args, **kwds):
@@ -1131,7 +1123,6 @@
             metaclass=_ExtensionsGenericMeta,
             extra=collections.ChainMap,
         ):
-
             __slots__ = ()
 
             def __new__(cls, *args, **kwds):
@@ -1550,7 +1541,6 @@
             bases="Protocol, Generic[T]" if OLD_GENERICS else "Protocol[T]"
         )
 
-
 elif PEP_560:
     from typing import _type_check, _GenericAlias, _collect_type_vars  # noqa
 
@@ -2473,7 +2463,6 @@
 if hasattr(typing, 'ParamSpec'):
     ParamSpec = typing.ParamSpec
 else:
-
     # Inherits from list as a workaround for Callable checks in Python < 3.9.2.
     class ParamSpec(list):
         """Parameter specification variable.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-4.0.0/podman/domain/containers.py 
new/podman-py-4.2.0/podman/domain/containers.py
--- old/podman-py-4.0.0/podman/domain/containers.py     2022-02-28 
17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/podman/domain/containers.py     2022-08-10 
15:03:52.000000000 +0200
@@ -2,6 +2,7 @@
 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
 
@@ -43,6 +44,8 @@
     def labels(self):
         """dict[str, str]: Returns labels associated with container."""
         with suppress(KeyError):
+            if "Labels" in self.attrs:
+                return self.attrs["Labels"]
             return self.attrs["Config"]["Labels"]
         return {}
 
@@ -92,7 +95,7 @@
         Keyword Args:
             author (str): Name of commit author
             changes (List[str]): Instructions to apply during commit
-            comment (List[str]): Instructions to apply while committing in 
Dockerfile format
+            comment (str): Commit message to include with Image, overrides 
keyword message
             conf (dict[str, Any]): Ignored.
             format (str): Format of the image manifest and metadata
             message (str): Commit message to include with Image
@@ -101,7 +104,7 @@
         params = {
             "author": kwargs.get("author"),
             "changes": kwargs.get("changes"),
-            "comment": kwargs.get("comment"),
+            "comment": kwargs.get("comment", kwargs.get("message")),
             "container": self.id,
             "format": kwargs.get("format"),
             "pause": kwargs.get("pause"),
@@ -112,7 +115,7 @@
         response.raise_for_status()
 
         body = response.json()
-        return ImagesManager(client=self.client).get(body["ID"])
+        return ImagesManager(client=self.client).get(body["Id"])
 
     def diff(self) -> List[Dict[str, int]]:
         """Report changes of a container's filesystem.
@@ -124,13 +127,14 @@
         response.raise_for_status()
         return response.json()
 
+    # pylint: disable=too-many-arguments,unused-argument
     def exec_run(
         self,
         cmd: Union[str, List[str]],
         stdout: bool = True,
         stderr: bool = True,
         stdin: bool = False,
-        tty: bool = False,
+        tty: bool = True,
         privileged: bool = False,
         user=None,
         detach: bool = False,
@@ -139,9 +143,7 @@
         environment: Union[Mapping[str, str], List[str]] = None,
         workdir: str = None,
         demux: bool = False,
-    ) -> Tuple[
-        Optional[int], Union[Iterator[bytes], Any, Tuple[bytes, bytes]]
-    ]:  # pylint: disable=too-many-arguments,unused-argument
+    ) -> Tuple[Optional[int], Union[Iterator[bytes], Any, Tuple[bytes, 
bytes]]]:
         """Run given command inside container and return results.
 
         Args:
@@ -164,16 +166,42 @@
             demux: Return stdout and stderr separately
 
         Returns:
-            TBD
+            First item is the command response code
+            Second item is the requests response content
 
         Raises:
             NotImplementedError: method not implemented.
             APIError: when service reports error
         """
-        if user is None:
-            user = "root"
-
-        raise NotImplementedError()
+        # pylint: disable-msg=too-many-locals
+        user = user or "root"
+        if isinstance(environment, dict):
+            environment = [f"{k}={v}" for k, v in environment.items()]
+        data = {
+            "AttachStderr": stderr,
+            "AttachStdin": stdin,
+            "AttachStdout": stdout,
+            "Cmd": cmd if isinstance(cmd, list) else shlex.split(cmd),
+            # "DetachKeys": detach,  # This is something else
+            "Env": environment,
+            "Privileged": privileged,
+            "Tty": tty,
+            "User": user,
+            "WorkingDir": workdir,
+        }
+        # create the exec instance
+        response = self.client.post(f"/containers/{self.name}/exec", 
data=json.dumps(data))
+        response.raise_for_status()
+        exec_id = response.json()['Id']
+        # start the exec instance, this will store command output
+        start_resp = self.client.post(
+            f"/exec/{exec_id}/start", data=json.dumps({"Detach": detach, 
"Tty": tty})
+        )
+        start_resp.raise_for_status()
+        # get and return exec information
+        response = self.client.get(f"/exec/{exec_id}/json")
+        response.raise_for_status()
+        return response.json().get('ExitCode'), start_resp.content
 
     def export(self, chunk_size: int = api.DEFAULT_CHUNK_SIZE) -> 
Iterator[bytes]:
         """Download container's filesystem contents as a tar archive.
@@ -250,6 +278,7 @@
             until (Union[datetime, int]): Show logs that occurred before the 
given
                 datetime or integer epoch (in seconds)
         """
+        stream = bool(kwargs.get("stream", False))
         params = {
             "follow": kwargs.get("follow", kwargs.get("stream", None)),
             "since": api.prepare_timestamp(kwargs.get("since")),
@@ -260,10 +289,10 @@
             "until": api.prepare_timestamp(kwargs.get("until")),
         }
 
-        response = self.client.get(f"/containers/{self.id}/logs", 
params=params)
+        response = self.client.get(f"/containers/{self.id}/logs", 
stream=stream, params=params)
         response.raise_for_status()
 
-        if bool(kwargs.get("stream", False)):
+        if stream:
             return api.stream_frames(response)
         return api.frames(response)
 
@@ -390,7 +419,7 @@
 
         with io.StringIO() as buffer:
             for entry in response.text:
-                buffer.writer(json.dumps(entry) + "\n")
+                buffer.write(json.dumps(entry) + "\n")
             return buffer.getvalue()
 
     @staticmethod
@@ -476,8 +505,9 @@
         """Block until the container enters given state.
 
         Keyword Args:
-            condition (str): Container state on which to release, values:
-                not-running (default), next-exit or removed.
+            condition (Union[str, List[str]]): Container state on which to 
release.
+                One or more of: "configured", "created", "running", "stopped",
+                "paused", "exited", "removing", "stopping".
             timeout (int): Ignored.
 
         Returns:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-4.0.0/podman/domain/containers_create.py 
new/podman-py-4.2.0/podman/domain/containers_create.py
--- old/podman-py-4.0.0/podman/domain/containers_create.py      2022-02-28 
17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/podman/domain/containers_create.py      2022-08-10 
15:03:52.000000000 +0200
@@ -53,7 +53,7 @@
             device_read_iops: Limit read rate (IO per second) from a device.
             device_write_bps: Limit write rate (bytes per second) from a 
device.
             device_write_iops: Limit write rate (IO per second) from a device.
-            devices (List[str): Expose host devices to the container, as a 
List[str] in the form
+            devices (List[str]): Expose host devices to the container, as a 
List[str] in the form
                 <path_on_host>:<path_in_container>:<cgroup_permissions>.
 
                 For example:
@@ -101,11 +101,34 @@
             mounts (List[Mount]): Specification for mounts to be added to the 
container. More
                 powerful alternative to volumes. Each item in the list is 
expected to be a
                 Mount object.
+                For example :
+                 [
+                    {
+                        "type": "bind",
+                        "source": "/a/b/c1",
+                        "target" "/d1",
+                        "read_only": True,
+                        "relabel": "Z"
+                    },
+                    {
+                        "type": "tmpfs",
+                        "source": "tmpfs", # If this was not passed, the 
regular directory
+                                           # would be created rather than 
tmpfs mount !!!
+                                           # as this will cause to have 
invalid entry
+                                           # in /proc/self/mountinfo
+                        "target" "/d2",
+                        "size": "100k",
+                        "chown": True
+                    }
+                ]
+
             name (str): The name for this container.
             nano_cpus (int):  CPU quota in units of 1e-9 CPUs.
-            network (str): Name of the network this container will be 
connected to at creation time.
-                You can connect to additional networks using Network.connect.
-                Incompatible with network_mode.
+            networks (Dict[str, Dict[str, Union[str, List[str]]):
+                Networks which will be connected to container during container 
creation
+                Values of the network configuration can be :
+                     - string
+                     - list of strings (e.g. Aliases)
             network_disabled (bool): Disable networking.
             network_mode (str): One of:
 
@@ -142,9 +165,9 @@
                     For example: {'2222/tcp': None}.
                 - A tuple of (address, port) if you want to specify the host 
interface.
                     For example: {'1111/tcp': ('127.0.0.1', 1111)}.
-                - A list of integers, if you want to bind multiple host ports 
to a single container
-                    port.
-                    For example: {'1111/tcp': [1234, 4567]}.
+                - A list of integers or tuples of (address, port), if you want 
to bind
+                  multiple host ports to a single container port.
+                    For example: {'1111/tcp': [1234, ("127.0.0.1", 4567)]}.
 
                     For example: {'9090': 7878, '10932/tcp': '8781',
                                   "8989/tcp": ("127.0.0.1", 9091)}
@@ -192,17 +215,26 @@
             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.
-            volumes (Dict[str, Dict[str, str]]): A dictionary to configure 
volumes mounted inside
-                the container. The key is either the host path or a volume 
name, and the value is
+            volumes (Dict[str, Dict[str, Union[str, list]]]): A dictionary to 
configure
+                volumes mounted inside the container.
+                The key is either the host path or a volume name, and the 
value is
                 a dictionary with the keys:
 
                 - bind: The path to mount the volume inside the container
                 - mode: Either rw to mount the volume read/write, or ro to 
mount it read-only.
+                        Kept for docker-py compatibility
+                - extended_mode: List of options passed to volume mount.
 
                 For example:
 
-                    {'/home/user1/': {'bind': '/mnt/vol2', 'mode': 'rw'},
-                     '/var/www': {'bind': '/mnt/vol1', 'mode': 'ro'}}
+                    {
+                        'test_bind_1':
+                            {'bind': '/mnt/vol1', 'mode': 'rw'},
+                        'test_bind_2':
+                            {'bind': '/mnt/vol2', 'extended_mode': ['ro', 
'noexec']},
+                         'test_bind_3':
+                            {'bind': '/mnt/vol3', 'extended_mode': ['noexec'], 
'mode': 'rw'}
+                    }
 
             volumes_from (List[str]): List of container names or IDs to get 
volumes from.
             working_dir (str): Path to the working directory.
@@ -265,7 +297,6 @@
                 "device_requests",  # FIXME In addition to device Major/Minor 
include path
                 "device_write_bps",  # FIXME In addition to device Major/Minor 
include path
                 "device_write_iops",  # FIXME In addition to device 
Major/Minor include path
-                "devices",  # FIXME In addition to device Major/Minor include 
path
                 "domainname",
                 "network_disabled",  # FIXME Where to map for Podman API?
                 "storage_opt",  # FIXME Where to map for Podman API?
@@ -320,7 +351,6 @@
 
         # Transform keywords into parameters
         params = {
-            "aliases": pop("aliases"),  # TODO document, podman only
             "annotations": pop("annotations"),  # TODO document, podman only
             "apparmor_profile": pop("apparmor_profile"),  # TODO document, 
podman only
             "cap_add": pop("cap_add"),
@@ -331,6 +361,7 @@
             "command": args.pop("command", args.pop("cmd", None)),
             "conmon_pid_file": pop("conmon_pid_file"),  # TODO document, 
podman only
             "containerCreateCommand": pop("containerCreateCommand"),  # TODO 
document, podman only
+            "devices": [],
             "dns_options": pop("dns_opt"),
             "dns_search": pop("dns_search"),
             "dns_server": pop("dns"),
@@ -358,6 +389,7 @@
             "name": pop("name"),
             "namespace": pop("namespace"),  # TODO What is this for?
             "network_options": pop("network_options"),  # TODO document, 
podman only
+            "networks": pop("networks"),
             "no_new_privileges": pop("no_new_privileges"),  # TODO document, 
podman only
             "oci_runtime": pop("runtime"),
             "oom_score_adj": pop("oom_score_adj"),
@@ -379,8 +411,6 @@
             "secrets": pop("secrets"),  # TODO document, podman only
             "selinux_opts": pop("security_opt"),
             "shm_size": to_bytes(pop("shm_size")),
-            "static_ip": pop("static_ip"),  # TODO document, podman only
-            "static_ipv6": pop("static_ipv6"),  # TODO document, podman only
             "static_mac": pop("mac_address"),
             "stdin": pop("stdin_open"),
             "stop_signal": pop("stop_signal"),
@@ -401,6 +431,9 @@
             "work_dir": pop("working_dir"),
         }
 
+        for device in args.pop("devices", []):
+            params["devices"].append({"path": device})
+
         for item in args.pop("exposed_ports", []):
             port, protocol = item.split("/")
             params["expose"][int(port)] = protocol
@@ -425,17 +458,24 @@
                 "type": item.get("type"),
             }
 
+            # some names are different for podman-py vs REST API due to 
compatibility with docker
+            # some (e.g. chown) despite listed in podman-run documentation 
fails with error
+            names_dict = {"read_only": "ro", "chown": "U"}
+
             options = []
-            if "read_only" in item:
-                options.append("ro")
-            if "consistency" in item:
-                options.append(f"consistency={item['consistency']}")
-            if "mode" in item:
-                options.append(f"mode={item['mode']}")
-            if "propagation" in item:
-                options.append(item["propagation"])
-            if "size" in item:
-                options.append(f"size={item['size']}")
+            simple_options = ["propagation", "relabel"]
+            bool_options = ["read_only", "U", "chown"]
+            regular_options = ["consistency", "mode", "size"]
+
+            for k, v in item.items():
+                option_name = names_dict.get(k, k)
+                if k in bool_options and v is True:
+                    options.append(option_name)
+                elif k in regular_options:
+                    options.append(f'{option_name}={v}')
+                elif k in simple_options:
+                    options.append(v)
+
             mount_point["options"] = options
 
             params["mounts"].append(mount_point)
@@ -461,9 +501,21 @@
                 port_map["host_ip"] = host[0]
                 port_map["host_port"] = int(host[1])
             elif isinstance(host, list):
-                raise ValueError(
-                    "Podman API does not support multiple port bound to a 
single host port."
-                )
+                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.")
 
@@ -492,7 +544,7 @@
             "kernelTCP": args.pop("kernel_memory_tcp", None),
             "limit": to_bytes(args.pop("mem_limit", None)),
             "reservation": to_bytes(args.pop("mem_reservation", None)),
-            "swap": args.pop("memswap_limit", None),
+            "swap": to_bytes(args.pop("memswap_limit", None)),
             "swappiness": args.pop("mem_swappiness", None),
             "useHierarchy": args.pop("mem_use_hierarchy", None),
         }
@@ -508,11 +560,18 @@
 
         for item in args.pop("volumes", {}).items():
             key, value = item
-            volume = {
-                "Name": key,
-                "Dest": value["bind"],
-                "Options": [value["mode"]] if "mode" in value else [],
-            }
+            extended_mode = value.get('extended_mode', [])
+            if not isinstance(extended_mode, list):
+                raise ValueError("'extended_mode' value should be a list")
+
+            options = extended_mode
+            mode = value.get('mode')
+            if mode is not None:
+                if not isinstance(mode, str):
+                    raise ValueError("'mode' value should be a str")
+                options.append(mode)
+
+            volume = {"Name": key, "Dest": value["bind"], "Options": options}
             params["volumes"].append(volume)
 
         if "cgroupns" in args:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-4.0.0/podman/domain/containers_run.py 
new/podman-py-4.2.0/podman/domain/containers_run.py
--- old/podman-py-4.0.0/podman/domain/containers_run.py 2022-02-28 
17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/podman/domain/containers_run.py 2022-08-10 
15:03:52.000000000 +0200
@@ -64,7 +64,7 @@
             container = self.create(image=image, command=command, **kwargs)
 
         container.start()
-        container.wait(condition="running")
+        container.wait(condition=["running", "exited"])
         container.reload()
 
         if kwargs.get("detach", False):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-4.0.0/podman/domain/images_manager.py 
new/podman-py-4.2.0/podman/domain/images_manager.py
--- old/podman-py-4.0.0/podman/domain/images_manager.py 2022-02-28 
17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/podman/domain/images_manager.py 2022-08-10 
15:03:52.000000000 +0200
@@ -9,6 +9,7 @@
 
 from podman import api
 from podman.api import Literal
+from podman.api.http_utils import encode_auth_header
 from podman.domain.images import Image
 from podman.domain.images_build import BuildMixin
 from podman.domain.manager import Manager
@@ -193,10 +194,13 @@
         Raises:
             APIError: when service returns an error
         """
-        # TODO set X-Registry-Auth
+        auth_config: Optional[Dict[str, str]] = kwargs.get("auth_config")
+
         headers = {
             # A base64url-encoded auth configuration
-            "X-Registry-Auth": ""
+            "X-Registry-Auth": encode_auth_header(auth_config)
+            if auth_config
+            else ""
         }
 
         params = {
@@ -204,7 +208,8 @@
             "tlsVerify": kwargs.get("tlsVerify"),
         }
 
-        name = urllib.parse.quote_plus(repository)
+        name = f'{repository}:{tag}' if tag else repository
+        name = urllib.parse.quote_plus(name)
         response = self.client.post(f"/images/{name}/push", params=params, 
headers=headers)
         response.raise_for_status(not_found=ImageNotFound)
 
@@ -244,7 +249,7 @@
     # pylint: disable=too-many-locals,too-many-branches
     def pull(
         self, repository: str, tag: Optional[str] = None, all_tags: bool = 
False, **kwargs
-    ) -> Union[Image, List[Image]]:
+    ) -> Union[Image, List[Image], Iterator[str]]:
         """Request Podman service to pull image(s) from repository.
 
         Args:
@@ -258,8 +263,11 @@
                 keys to be valid.
             platform (str) ??? Platform in the format os[/arch[/variant]]
             tls_verify (bool) - Require TLS verification. Default: True.
+            stream (bool) - When True, the pull progress will be published as 
received.
+                Default: False.
 
         Returns:
+            When stream is True, return a generator publishing the service 
pull progress.
             If all_tags is True, return list of Image's rather than Image 
pulled.
 
         Raises:
@@ -273,6 +281,15 @@
             else:
                 tag = "latest"
 
+        auth_config: Optional[Dict[str, str]] = kwargs.get("auth_config")
+
+        headers = {
+            # A base64url-encoded auth configuration
+            "X-Registry-Auth": encode_auth_header(auth_config)
+            if auth_config
+            else ""
+        }
+
         params = {
             "reference": repository,
             "tlsVerify": kwargs.get("tls_verify"),
@@ -294,26 +311,23 @@
             if len(tokens) > 2:
                 params["Variant"] = tokens[2]
 
-        if "auth_config" in kwargs:
-            username = kwargs["auth_config"].get("username")
-            password = kwargs["auth_config"].get("password")
-            if username is None or password is None:
-                raise ValueError("'auth_config' requires keys 'username' and 
'password'")
-            params["credentials"] = f"{username}:{password}"
-
-        response = self.client.post("/images/pull", params=params)
+        stream = kwargs.get("stream", False)
+        response = self.client.post("/images/pull", params=params, 
stream=stream, headers=headers)
         response.raise_for_status(not_found=ImageNotFound)
 
+        if stream:
+            return response.iter_lines()
+
         for item in response.iter_lines():
-            body = json.loads(item)
-            if all_tags and "images" in body:
+            obj = json.loads(item)
+            if all_tags and "images" in obj:
                 images: List[Image] = []
-                for name in body["images"]:
+                for name in obj["images"]:
                     images.append(self.get(name))
                 return images
 
-            if "id" in body:
-                return self.get(body["id"])
+            if "id" in obj:
+                return self.get(obj["id"])
         return self.resource()
 
     def remove(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-4.0.0/podman/domain/manager.py 
new/podman-py-4.2.0/podman/domain/manager.py
--- old/podman-py-4.0.0/podman/domain/manager.py        2022-02-28 
17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/podman/domain/manager.py        2022-08-10 
15:03:52.000000000 +0200
@@ -5,8 +5,8 @@
 
 from podman.api.client import APIClient
 
-# Methods use this Type when a sub-class of PodmanResource is expected.
-PodmanResourceType = TypeVar("PodmanResourceType", bound="PodmanResource")
+# Methods use this Type when a subclass of PodmanResource is expected.
+PodmanResourceType: TypeVar = TypeVar("PodmanResourceType", 
bound="PodmanResource")
 
 
 class PodmanResource(ABC):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-4.0.0/podman/domain/system.py 
new/podman-py-4.2.0/podman/domain/system.py
--- old/podman-py-4.0.0/podman/domain/system.py 2022-02-28 17:35:01.000000000 
+0100
+++ new/podman-py-4.2.0/podman/domain/system.py 2022-08-10 15:03:52.000000000 
+0200
@@ -3,6 +3,7 @@
 from typing import Any, Dict, Optional
 
 from podman.api.client import APIClient
+from podman import api
 
 logger = logging.getLogger("podman.system")
 
@@ -40,8 +41,8 @@
         password: Optional[str] = None,
         email: Optional[str] = None,
         registry: Optional[str] = None,
-        reauth: bool = False,
-        dockercfg_path: Optional[str] = None,
+        reauth: Optional[bool] = False,  # pylint: disable=unused-argument
+        dockercfg_path: Optional[str] = None,  # pylint: 
disable=unused-argument
     ) -> Dict[str, Any]:
         """Log into Podman service.
 
@@ -50,12 +51,27 @@
             password: Registry plaintext password
             email: Registry account email address
             registry: URL for registry access. For example,
+            reauth: Ignored: If True, refresh existing authentication. 
Default: False
+            dockercfg_path: Ignored: Path to custom configuration file.
                 https://quay.io/v2
-            reauth: If True, refresh existing authentication. Default: False
-            dockercfg_path: Path to custom configuration file.
-                Default: $HOME/.config/containers/config.json
         """
 
+        payload = {
+            "username": username,
+            "password": password,
+            "email": email,
+            "serveraddress": registry,
+        }
+        payload = api.prepare_body(payload)
+        response = self.client.post(
+            path="/auth",
+            headers={"Content-type": "application/json"},
+            data=payload,
+            compatible=True,
+        )
+        response.raise_for_status()
+        return response.json()
+
     def ping(self) -> bool:
         """Returns True if service responded with OK."""
         response = self.client.head("/_ping")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-4.0.0/podman/tests/__init__.py 
new/podman-py-4.2.0/podman/tests/__init__.py
--- old/podman-py-4.0.0/podman/tests/__init__.py        2022-02-28 
17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/podman/tests/__init__.py        2022-08-10 
15:03:52.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.0.0/libpod";
+LIBPOD_URL = "http://%2Frun%2Fapi.sock/v4.2.0/libpod";
 COMPATIBLE_URL = "http://%2Frun%2Fapi.sock/v1.40";
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/podman-py-4.0.0/podman/tests/integration/test_container_create.py 
new/podman-py-4.2.0/podman/tests/integration/test_container_create.py
--- old/podman-py-4.0.0/podman/tests/integration/test_container_create.py       
2022-02-28 17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/podman/tests/integration/test_container_create.py       
2022-08-10 15:03:52.000000000 +0200
@@ -1,9 +1,10 @@
 import unittest
 
+import re
+
 import podman.tests.integration.base as base
 from podman import PodmanClient
 
-
 # @unittest.skipIf(os.geteuid() != 0, 'Skipping, not running as root')
 
 
@@ -23,6 +24,34 @@
         for container in self.containers:
             container.remove(force=True)
 
+    def test_container_volume_mount(self):
+        with self.subTest("Check volume mount"):
+            volumes = {
+                'test_bind_1': {'bind': '/mnt/vol1', 'mode': 'rw'},
+                'test_bind_2': {'bind': '/mnt/vol2', 'extended_mode': ['ro', 
'noexec']},
+                'test_bind_3': {'bind': '/mnt/vol3', 'extended_mode': 
['noexec'], 'mode': 'rw'},
+            }
+            container = self.client.containers.create(self.alpine_image, 
volumes=volumes)
+            container_mounts = container.attrs.get('Mounts', {})
+            self.assertEqual(len(container_mounts), len(volumes))
+
+            for mount in container_mounts:
+                name = mount.get('Name')
+                self.assertIn(name, volumes)
+                test_mount = volumes.get(name)
+                test_mode = test_mount.get('mode', '')
+                test_extended_mode = test_mount.get('extended_mode', [])
+                # check RO/RW
+                if 'ro' in test_mode or 'ro' in test_extended_mode:
+                    self.assertEqual(mount.get('RW'), False)
+
+                if 'rw' in test_mode or 'rw' in test_extended_mode:
+                    self.assertEqual(mount.get('RW'), True)
+
+                other_options = [o for o in test_extended_mode if o not in 
['ro', 'rw']]
+                for o in other_options:
+                    self.assertIn(o, mount.get('Options'))
+
     def test_container_extra_hosts(self):
         """Test Container Extra hosts"""
         extra_hosts = {"host1 host3": "127.0.0.2", "host2": "127.0.0.3"}
@@ -42,11 +71,11 @@
             proper_container.start()
             proper_container.wait()
             logs = b"\n".join(proper_container.logs()).decode()
-            formatted_hosts = [f"{ip} {hosts}" for hosts, ip in 
extra_hosts.items()]
+            formatted_hosts = [f"{ip}\t{hosts}" for hosts, ip in 
extra_hosts.items()]
             for hosts_entry in formatted_hosts:
                 self.assertIn(hosts_entry, logs)
 
-    def _test_memory_limit(self, parameter_name, host_config_name):
+    def _test_memory_limit(self, parameter_name, host_config_name, 
set_mem_limit=False):
         """Base for tests which checks memory limits"""
         memory_limit_tests = [
             {'value': 1000, 'expected_value': 1000},
@@ -58,19 +87,72 @@
         ]
 
         for test in memory_limit_tests:
-            container = self.client.containers.create(
-                self.alpine_image, **{parameter_name: test['value']}
-            )
+            parameters = {parameter_name: test['value']}
+            if set_mem_limit:
+                parameters['mem_limit'] = test['expected_value'] - 100
+
+            container = self.client.containers.create(self.alpine_image, 
**parameters)
             self.containers.append(container)
             self.assertEqual(
                 container.attrs.get('HostConfig', 
dict()).get(host_config_name),
                 test['expected_value'],
             )
 
+    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')
+                ]
+            )
+        )
+
     def test_container_mem_limit(self):
         """Test passing memory limit"""
         self._test_memory_limit('mem_limit', 'Memory')
 
+    def test_container_memswap_limit(self):
+        """Test passing memory swap limit"""
+        self._test_memory_limit('memswap_limit', 'MemorySwap', 
set_mem_limit=True)
+
     def test_container_mem_reservation(self):
         """Test passing memory reservation"""
         self._test_memory_limit('mem_reservation', 'MemoryReservation')
@@ -79,6 +161,100 @@
         """Test passing shared memory size"""
         self._test_memory_limit('shm_size', 'ShmSize')
 
+    def test_container_mounts(self):
+        """Test passing mounts"""
+        with self.subTest("Check bind mount"):
+            mount = {
+                "type": "bind",
+                "source": "/etc/hosts",
+                "target": "/test",
+                "read_only": True,
+                "relabel": "Z",
+            }
+            container = self.client.containers.create(
+                self.alpine_image, command=["cat", "/test"], mounts=[mount]
+            )
+            self.containers.append(container)
+            self.assertIn(
+                f"{mount['source']}:{mount['target']}:ro,Z,rprivate,rbind",
+                container.attrs.get('HostConfig', {}).get('Binds', list()),
+            )
+
+            # check if container can be started and exits with EC == 0
+            container.start()
+            container.wait()
+
+            self.assertEqual(container.attrs.get('State', 
dict()).get('ExitCode', 256), 0)
+
+        with self.subTest("Check tmpfs mount"):
+            mount = {"type": "tmpfs", "source": "tmpfs", "target": "/test", 
"size": "456k"}
+            container = self.client.containers.create(
+                self.alpine_image, command=["df", "-h"], mounts=[mount]
+            )
+            self.containers.append(container)
+            self.assertEqual(
+                container.attrs.get('HostConfig', {}).get('Tmpfs', 
{}).get(mount['target']),
+                f"size={mount['size']},rw,rprivate,nosuid,nodev,tmpcopyup",
+            )
+
+            container.start()
+            container.wait()
+
+            logs = b"\n".join(container.logs()).decode()
+
+            self.assertTrue(
+                re.search(
+                    rf"{mount['size'].replace('k', 
'.0K')}.*?{mount['target']}",
+                    logs,
+                    flags=re.MULTILINE,
+                )
+            )
+
+    def test_container_devices(self):
+        devices = ["/dev/null:/dev/foo", "/dev/zero:/dev/bar"]
+        container = self.client.containers.create(
+            self.alpine_image, devices=devices, command=["ls", "-l", "/dev/"]
+        )
+        self.containers.append(container)
+
+        container_devices = container.attrs.get('HostConfig', 
{}).get('Devices', [])
+        with self.subTest("Check devices in container object"):
+            for device in devices:
+                path_on_host, path_in_container = device.split(':', 1)
+                self.assertTrue(
+                    any(
+                        [
+                            c.get('PathOnHost') == path_on_host
+                            and c.get('PathInContainer') == path_in_container
+                            for c in container_devices
+                        ]
+                    )
+                )
+
+        with self.subTest("Check devices in running container object"):
+            container.start()
+            container.wait()
+
+            logs = b"\n".join(container.logs()).decode()
+
+            device_regex = r'(\d+, *?\d+).*?{}\n'
+
+            for device in devices:
+                # check whether device exists
+                source_device, destination_device = device.split(':', 1)
+                source_match = re.search(
+                    device_regex.format(source_device.rsplit("/", 1)[-1]), logs
+                )
+                destination_match = re.search(
+                    device_regex.format(destination_device.rsplit("/", 
1)[-1]), logs
+                )
+
+                self.assertIsNotNone(source_match)
+                self.assertIsNotNone(destination_match)
+
+                # validate if proper device was added (by major/minor numbers)
+                self.assertEqual(source_match.group(1), 
destination_match.group(1))
+
 
 if __name__ == '__main__':
     unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/podman-py-4.0.0/podman/tests/integration/test_containers.py 
new/podman-py-4.2.0/podman/tests/integration/test_containers.py
--- old/podman-py-4.0.0/podman/tests/integration/test_containers.py     
2022-02-28 17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/podman/tests/integration/test_containers.py     
2022-08-10 15:03:52.000000000 +0200
@@ -146,6 +146,17 @@
             with self.assertRaises(NotFound):
                 self.client.containers.get(top_ctnr.id)
 
+    def test_container_commit(self):
+        """Commit new image."""
+        busybox = self.client.images.pull("quay.io/libpod/busybox", 
tag="latest")
+        container = self.client.containers.create(
+            busybox, command=["echo", f"{random.getrandbits(160):x}"]
+        )
+
+        image = container.commit(repository="busybox.local", tag="unittest")
+        self.assertIn("localhost/busybox.local:unittest", 
image.attrs["RepoTags"])
+        busybox.remove(force=True)
+
 
 if __name__ == '__main__':
     unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/podman-py-4.0.0/podman/tests/integration/test_images.py 
new/podman-py-4.2.0/podman/tests/integration/test_images.py
--- old/podman-py-4.0.0/podman/tests/integration/test_images.py 2022-02-28 
17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/podman/tests/integration/test_images.py 2022-08-10 
15:03:52.000000000 +0200
@@ -14,13 +14,18 @@
 #
 """Images integration tests."""
 import io
+import queue
 import tarfile
+import threading
+import types
 import unittest
+from contextlib import suppress
+from datetime import datetime, timedelta
 
 import podman.tests.integration.base as base
 from podman import PodmanClient
 from podman.domain.images import Image
-from podman.errors import ImageNotFound, APIError
+from podman.errors import APIError, ImageNotFound
 
 
 # @unittest.skipIf(os.geteuid() != 0, 'Skipping, not running as root')
@@ -124,3 +129,7 @@
         image, stream = self.client.images.build(fileobj=buffer)
         self.assertIsNotNone(image)
         self.assertIsNotNone(image.id)
+
+    def test_pull_stream(self):
+        generator = self.client.images.pull("ubi8", tag="latest", stream=True)
+        self.assertIsInstance(generator, types.GeneratorType)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/podman-py-4.0.0/podman/tests/integration/test_manifests.py 
new/podman-py-4.2.0/podman/tests/integration/test_manifests.py
--- old/podman-py-4.0.0/podman/tests/integration/test_manifests.py      
2022-02-28 17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/podman/tests/integration/test_manifests.py      
2022-08-10 15:03:52.000000000 +0200
@@ -66,7 +66,7 @@
 
         with self.subTest("Remove digest"):
             manifest.remove(self.alpine_image.attrs["RepoDigests"][0])
-            self.assertEqual(len(manifest.attrs["manifests"]), 0)
+            self.assertIsNone(manifest.attrs["manifests"])
 
     def test_create_409(self):
         """Test that invalid Image names are caught and not corrupt storage."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/podman-py-4.0.0/podman/tests/integration/test_system.py 
new/podman-py-4.2.0/podman/tests/integration/test_system.py
--- old/podman-py-4.0.0/podman/tests/integration/test_system.py 2022-02-28 
17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/podman/tests/integration/test_system.py 2022-08-10 
15:03:52.000000000 +0200
@@ -16,6 +16,7 @@
 
 import podman.tests.integration.base as base
 from podman import PodmanClient
+from podman.errors import APIError
 
 
 class SystemIntegrationTest(base.IntegrationTest):
@@ -44,3 +45,15 @@
         self.assertTrue('Images' in output)
         self.assertTrue('Containers' in output)
         self.assertTrue('Volumes' in output)
+
+    def test_login(self):
+        """integration: system login call"""
+        # here, we just test the sanity of the endpoint
+        # confirming that we get through to podman, and get tcp rejected.
+        with self.assertRaises(APIError) as e:
+            next(
+                self.client.login(
+                    "fake_user", "fake_password", 
"fake_email@fake_domain.test", "fake_registry"
+                )
+            )
+        self.assertIn("lookup fake_registry: no such host", 
e.exception.explanation)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-4.0.0/podman/tests/unit/test_container.py 
new/podman-py-4.2.0/podman/tests/unit/test_container.py
--- old/podman-py-4.0.0/podman/tests/unit/test_container.py     2022-02-28 
17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/podman/tests/unit/test_container.py     2022-08-10 
15:03:52.000000000 +0200
@@ -306,7 +306,7 @@
             
"&container=87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd&format=docker"
             "&pause=True&repo=quay.local&tag=unittest",
             status_code=201,
-            json={"ID": 
"d2459aad75354ddc9b5b23f863786e279637125af6ba4d4a83f881866b3c903f"},
+            json={"Id": 
"d2459aad75354ddc9b5b23f863786e279637125af6ba4d4a83f881866b3c903f"},
         )
         get_adapter = mock.get(
             tests.LIBPOD_URL
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/podman-py-4.0.0/podman/tests/unit/test_imagesmanager.py 
new/podman-py-4.2.0/podman/tests/unit/test_imagesmanager.py
--- old/podman-py-4.0.0/podman/tests/unit/test_imagesmanager.py 2022-02-28 
17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/podman/tests/unit/test_imagesmanager.py 2022-08-10 
15:03:52.000000000 +0200
@@ -417,7 +417,7 @@
 
     @requests_mock.Mocker()
     def test_push(self, mock):
-        mock.post(tests.LIBPOD_URL + "/images/quay.io%2ffedora/push")
+        mock.post(tests.LIBPOD_URL + "/images/quay.io%2Ffedora%3Alatest/push")
 
         report = self.client.images.push("quay.io/fedora", "latest")
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-4.0.0/podman/version.py 
new/podman-py-4.2.0/podman/version.py
--- old/podman-py-4.0.0/podman/version.py       2022-02-28 17:35:01.000000000 
+0100
+++ new/podman-py-4.2.0/podman/version.py       2022-08-10 15:03:52.000000000 
+0200
@@ -1,4 +1,4 @@
 """Version of PodmanPy."""
 
-__version__ = "4.0.0"
+__version__ = "4.2.0"
 __compatible_version__ = "1.40"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-4.0.0/pyproject.toml 
new/podman-py-4.2.0/pyproject.toml
--- old/podman-py-4.0.0/pyproject.toml  2022-02-28 17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/pyproject.toml  2022-08-10 15:03:52.000000000 +0200
@@ -1,7 +1,7 @@
 [tool.black]
 line-length = 100
 skip-string-normalization = true
-experimental-string-processing = true
+preview = true
 target-version = ["py36"]
 include = '\.pyi?$'
 exclude = '''
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-4.0.0/python-podman.spec.rpkg 
new/podman-py-4.2.0/python-podman.spec.rpkg
--- old/podman-py-4.0.0/python-podman.spec.rpkg 1970-01-01 01:00:00.000000000 
+0100
+++ new/podman-py-4.2.0/python-podman.spec.rpkg 2022-08-10 15:03:52.000000000 
+0200
@@ -0,0 +1,109 @@
+# For automatic rebuilds in COPR
+
+# The following tag is to get correct syntax highlighting for this file in vim 
text editor
+# vim: syntax=spec
+
+%global debug_package %{nil}
+
+%if ! 0%{?fedora} && 0%{?rhel} <= 8
+%global old_rhel 1
+%else
+%global old_rhel 0
+%endif
+
+%global pypi_name podman
+%global desc %{pypi_name} is a library of bindings to use the RESTful API for 
Podman.
+
+# git_dir_name returns repository name derived from remote Git repository URL
+Name: python-podman
+
+Epoch: 101
+
+# git_dir_version returns version based on commit and tag history of the Git 
project
+Version:    {{{ git_dir_version }}}
+
+# This can be useful later for adding downstream patches
+Release:    1%{?dist}
+
+# Basic description of the package
+Summary: Manage Pods, Containers and Container Images
+
+# License. We assume GPLv2+ here.
+License:   ASL 2.0
+
+# Home page of the project. Can also point to the public Git repository page.
+URL:        https://github.com/containers/podman-py
+
+# Detailed information about the source Git repository and the source commit
+# for the created rpm package
+VCS:        {{{ git_dir_vcs }}}
+
+# git_dir_pack macro places the repository content (the source files) into a 
tarball
+# and returns its filename. The tarball will be used to build the rpm.
+Source:     {{{ git_dir_pack }}}
+
+%description
+%desc
+
+%package -n python%{python3_pkgversion}-%{pypi_name}
+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
+Requires: python%{python3_pkgversion}-pyxdg
+Requires: python%{python3_pkgversion}-requests
+%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}}
+
+%description -n python%{python3_pkgversion}-%{pypi_name}
+%desc
+
+# The following four sections already describe the rpm build process itself.
+# prep will extract the tarball defined as Source above and descend into it.
+%prep
+{{{ git_dir_setup_macro }}}
+
+%if ! %{?old_rhel}
+%generate_buildrequires
+%pyproject_buildrequires %{?with_tests:-t}
+%endif
+
+# This will invoke `make` command in the directory with the extracted sources.
+%build
+%if %{?old_rhel}
+%py3_build
+%else
+%pyproject_wheel
+%endif
+
+%install
+%if %{?old_rhel}
+%py3_install
+%else
+%pyproject_install
+%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
+%license LICENSE
+%doc README.md
+%{python3_sitelib}/podman/*
+%{python3_sitelib}/podman-*/*
+
+# Finally, changes from the latest release of your application are generated 
from
+# your project's Git history. It will be empty until you make first annotated 
Git tag.
+%changelog
+{{{ git_dir_changelog }}}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-4.0.0/tox.ini new/podman-py-4.2.0/tox.ini
--- old/podman-py-4.0.0/tox.ini 2022-02-28 17:35:01.000000000 +0100
+++ new/podman-py-4.2.0/tox.ini 2022-08-10 15:03:52.000000000 +0200
@@ -1,6 +1,6 @@
 [tox]
 minversion = 3.2.0
-envlist = pylint,coverage,py36,py38,py39,py310
+envlist = pylint,coverage,py36,py38,py39,py310,py311
 ignore_basepython_conflict = true
 
 [testenv]

Reply via email to