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 2024-08-03 20:04:43
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-podman (Old)
 and      /work/SRC/openSUSE:Factory/.python-podman.new.7232 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-podman"

Sat Aug  3 20:04:43 2024 rev:18 rq:1191231 version:5.2.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-podman/python-podman.changes      
2024-03-25 21:19:23.790095387 +0100
+++ /work/SRC/openSUSE:Factory/.python-podman.new.7232/python-podman.changes    
2024-08-03 20:04:50.675809032 +0200
@@ -1,0 +2,37 @@
+Fri Aug  2 14:04:13 UTC 2024 - Johannes Kastl 
<opensuse_buildserv...@ojkastl.de>
+
+- update to 5.2.0:
+  * Fix the TypeError exception in the images.prune method by
+    @milanbalazs in #412
+  * Bump version to 5.2.0 by @inknos in #414
+
+-------------------------------------------------------------------
+Fri Aug  2 13:53:22 UTC 2024 - Johannes Kastl 
<opensuse_buildserv...@ojkastl.de>
+
+- update to 5.1.0:
+  * Fix dns_option typo by @robbmanes in #386
+  * Fixes encoding of X-Registry-auth HTTP Header value from Base64
+    to url_safe Base64 by @apozsuse in #385
+  * Include py.typed marker file. by @jonded94 in #381
+  * [skip-ci] Packit: enable c10s downstream sync by @lsm5 in #388
+  * ignore proxies from the env vars when using UNIX Domain Sockets
+    by @eighthave in #391
+  * Fix Pylint E0606 for undefined variable after else by @inknos
+    in #392
+  * [skip-ci] Packit: use default update_release behavior by @lsm5
+    in #393
+  * Update OWNERS by @jwhonce in #394
+  * Fix README TypeError when one container is running by @inknos
+    in #395
+  * Remove Fedora release number from task names by @cevich in #396
+  * Add python 3.12 support and remove python xdg by @inknos in
+    #401
+  * Update index.rst Client -> PodmanClient by @jwoehr in #405
+  * Implementing the functionality of the 'named' argument of the
+    'Image.save' method by @milanbalazs in #406
+  * Fix the locally non-existent image fails with AttributeError by
+    @milanbalazs in #408
+  * Enable demux option in exec_run by @inknos in #410
+  * Bump version to 5.1.0 by @inknos in #409
+
+-------------------------------------------------------------------

Old:
----
  podman-5.0.0.tar.gz

New:
----
  podman-5.2.0.tar.gz

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

Other differences:
------------------
++++++ python-podman.spec ++++++
--- /var/tmp/diff_new_pack.BxTKP8/_old  2024-08-03 20:04:51.407839106 +0200
+++ /var/tmp/diff_new_pack.BxTKP8/_new  2024-08-03 20:04:51.407839106 +0200
@@ -26,7 +26,7 @@
 %bcond_with test
 %endif
 Name:           python-podman%{psuffix}
-Version:        5.0.0
+Version:        5.2.0
 Release:        0
 Summary:        A library to interact with a Podman server
 License:        Apache-2.0
@@ -35,7 +35,6 @@
 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 tomli >= 1.2.3 if python-base < 3.11}
-BuildRequires:  %{python_module pyxdg >= 0.26}
 BuildRequires:  %{python_module requests >= 2.24}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  %{python_module pip}
@@ -43,7 +42,6 @@
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 Requires:       (python-tomli >= 1.2.3 if python-base < 3.11)
-Requires:       python-pyxdg
 Requires:       python-requests
 Requires:       python-urllib3
 BuildArch:      noarch

++++++ podman-5.0.0.tar.gz -> podman-5.2.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/.cirrus.yml 
new/podman-py-5.2.0/.cirrus.yml
--- old/podman-py-5.0.0/.cirrus.yml     2024-03-22 22:46:27.000000000 +0100
+++ new/podman-py-5.2.0/.cirrus.yml     2024-08-02 15:18:25.000000000 +0200
@@ -14,8 +14,6 @@
     ####
     #### Cache-image names to test with (double-quotes around names are 
critical)
     ####
-    FEDORA_NAME: "fedora-39"
-
     # Google-cloud VM Images
     IMAGE_SUFFIX: "c20240320t153921z-f39f38d13"
     FEDORA_CACHE_IMAGE_NAME: "fedora-podman-py-${IMAGE_SUFFIX}"
@@ -51,7 +49,7 @@
         - make lint
 
 test_task:
-    name: "Test on $FEDORA_NAME"
+    name: "Test on Fedora"
     alias: test
 
     depends_on:
@@ -64,7 +62,7 @@
         - ${SCRIPT_BASE}/test.sh
 
 latest_task:
-    name: "Test Podman main on $FEDORA_NAME"
+    name: "Test Podman main on Fedora"
     alias: latest
     allow_failures: true
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/.packit.yaml 
new/podman-py-5.2.0/.packit.yaml
--- old/podman-py-5.0.0/.packit.yaml    2024-03-22 22:46:27.000000000 +0100
+++ new/podman-py-5.2.0/.packit.yaml    2024-08-02 15:18:25.000000000 +0200
@@ -3,33 +3,67 @@
 # https://packit.dev/docs/configuration/
 
 downstream_package_name: python-podman
-specfile_path: rpm/python-podman.spec
 upstream_tag_template: v{version}
 
+packages:
+  python-podman-fedora:
+    pkg_tool: fedpkg
+    specfile_path: rpm/python-podman.spec
+  python-podman-centos:
+    pkg_tool: centpkg
+    specfile_path: rpm/python-podman.spec
+  python-podman-rhel:
+    specfile_path: rpm/python-podman.spec
+
 srpm_build_deps:
   - make
 
 jobs:
+  # Copr builds for Fedora
   - job: copr_build
     trigger: pull_request
+    packages: [python-podman-fedora]
     targets:
       - fedora-all
-      - centos-stream-8
+
+  # Copr builds for CentOS Stream
+  - job: copr_build
+    trigger: pull_request
+    packages: [python-podman-centos]
+    targets:
+      - centos-stream-10
       - centos-stream-9
 
+  # Copr builds for RHEL
+  - job: copr_build
+    trigger: pull_request
+    packages: [python-podman-rhel]
+    targets:
+      - epel-9
+
   # Run on commit to main branch
   - job: copr_build
     trigger: commit
+    packages: [python-podman-fedora]
     branch: main
     owner: rhcontainerbot
     project: podman-next
 
+  # Downstream sync for Fedora
   - job: propose_downstream
     trigger: release
-    update_release: false
+    packages: [python-podman-fedora]
     dist_git_branches:
       - fedora-all
 
+  # Downstream sync for CentOS Stream
+  # TODO: c9s enablement being tracked in 
https://issues.redhat.com/browse/RUN-2123
+  - job: propose_downstream
+    trigger: release
+    packages: [python-podman-centos]
+    dist_git_branches:
+      - c10s
+
   - job: koji_build
     trigger: commit
     dist_git_branches:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/Makefile new/podman-py-5.2.0/Makefile
--- old/podman-py-5.0.0/Makefile        2024-03-22 22:46:27.000000000 +0100
+++ new/podman-py-5.2.0/Makefile        2024-08-02 15:18:25.000000000 +0200
@@ -8,7 +8,7 @@
 EPOCH_TEST_COMMIT ?= $(shell git merge-base $${DEST_BRANCH:-main} HEAD)
 HEAD ?= HEAD
 
-export PODMAN_VERSION ?= "5.0.0"
+export PODMAN_VERSION ?= "5.2.0"
 
 .PHONY: podman
 podman:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/OWNERS new/podman-py-5.2.0/OWNERS
--- old/podman-py-5.0.0/OWNERS  2024-03-22 22:46:27.000000000 +0100
+++ new/podman-py-5.2.0/OWNERS  2024-08-02 15:18:25.000000000 +0200
@@ -1,6 +1,5 @@
 approvers:
   - baude
-  - cdoern
   - edsantiago
   - giuseppe
   - jwhonce
@@ -27,3 +26,4 @@
   - TomSweeneyRedHat
   - umohnani8
   - vrothberg
+  - inknos
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/README.md 
new/podman-py-5.2.0/README.md
--- old/podman-py-5.0.0/README.md       2024-03-22 22:46:27.000000000 +0100
+++ new/podman-py-5.2.0/README.md       2024-08-02 15:18:25.000000000 +0200
@@ -35,9 +35,12 @@
 
     # find all containers
     for container in client.containers.list():
-        first_name = container['Names'][0]
-        container = client.containers.get(first_name)
+        # After a list call you would probably want to reload the container
+        # to get the information about the variables such as status.
+        # Note that list() ignores the sparse option and assumes True by 
default.
+        container.reload()
         print(container, container.id, "\n")
+        print(container, container.status, "\n")
 
         # available fields
         print(sorted(container.attrs.keys()))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/docs/source/index.rst 
new/podman-py-5.2.0/docs/source/index.rst
--- old/podman-py-5.0.0/docs/source/index.rst   2024-03-22 22:46:27.000000000 
+0100
+++ new/podman-py-5.2.0/docs/source/index.rst   2024-08-02 15:18:25.000000000 
+0200
@@ -36,7 +36,7 @@
 
     import podman
 
-    with podman.Client() as client:
+    with podman.PodmanClient() as client:
         if client.ping():
             images = client.images.list()
             for image in images:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/podman/api/client.py 
new/podman-py-5.2.0/podman/api/client.py
--- old/podman-py-5.0.0/podman/api/client.py    2024-03-22 22:46:27.000000000 
+0100
+++ new/podman-py-5.2.0/podman/api/client.py    2024-08-02 15:18:25.000000000 
+0200
@@ -145,6 +145,8 @@
         if self.base_url.scheme == "http+unix":
             self.mount("http://";, UDSAdapter(self.base_url.geturl(), 
**adapter_kwargs))
             self.mount("https://";, UDSAdapter(self.base_url.geturl(), 
**adapter_kwargs))
+            # ignore proxies from the env vars
+            self.trust_env = False
 
         elif self.base_url.scheme == "http+ssh":
             self.mount("http://";, SSHAdapter(self.base_url.geturl(), 
**adapter_kwargs))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/podman/api/http_utils.py 
new/podman-py-5.2.0/podman/api/http_utils.py
--- old/podman-py-5.0.0/podman/api/http_utils.py        2024-03-22 
22:46:27.000000000 +0100
+++ new/podman-py-5.2.0/podman/api/http_utils.py        2024-08-02 
15:18:25.000000000 +0200
@@ -100,4 +100,4 @@
 
 
 def encode_auth_header(auth_config: Dict[str, str]) -> str:
-    return base64.b64encode(json.dumps(auth_config).encode('utf-8'))
+    return base64.urlsafe_b64encode(json.dumps(auth_config).encode('utf-8'))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/podman/api/output_utils.py 
new/podman-py-5.2.0/podman/api/output_utils.py
--- old/podman-py-5.0.0/podman/api/output_utils.py      1970-01-01 
01:00:00.000000000 +0100
+++ new/podman-py-5.2.0/podman/api/output_utils.py      2024-08-02 
15:18:25.000000000 +0200
@@ -0,0 +1,49 @@
+"""Utility functions for dealing with stdout and stderr."""
+
+HEADER_SIZE = 8
+STDOUT = 1
+STDERR = 2
+
+
+# pylint: disable=line-too-long
+def demux_output(data_bytes):
+    """Demuxes the output of a container stream into stdout and stderr streams.
+
+    Stream data is expected to be in the following format:
+    - 1 byte: stream type (1=stdout, 2=stderr)
+    - 3 bytes: padding
+    - 4 bytes: payload size (big-endian)
+    - N bytes: payload data
+    ref: 
https://docs.podman.io/en/latest/_static/api.html?version=v5.0#tag/containers/operation/ContainerAttachLibpod
+
+    Args:
+        data_bytes: Bytes object containing the combined stream data.
+
+    Returns:
+        A tuple containing two bytes objects: (stdout, stderr).
+    """
+    stdout = b""
+    stderr = b""
+    while len(data_bytes) >= HEADER_SIZE:
+        # Extract header information
+        header, data_bytes = data_bytes[:HEADER_SIZE], data_bytes[HEADER_SIZE:]
+        stream_type = header[0]
+        payload_size = int.from_bytes(header[4:HEADER_SIZE], "big")
+        # Check if data is sufficient for payload
+        if len(data_bytes) < payload_size:
+            break  # Incomplete frame, wait for more data
+
+        # Extract and process payload
+        payload = data_bytes[:payload_size]
+        if stream_type == STDOUT:
+            stdout += payload
+        elif stream_type == STDERR:
+            stderr += payload
+        else:
+            # todo: Handle unexpected stream types
+            pass
+
+        # Update data for next frame
+        data_bytes = data_bytes[payload_size:]
+
+    return stdout, stderr
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/podman/api/path_utils.py 
new/podman-py-5.2.0/podman/api/path_utils.py
--- old/podman-py-5.0.0/podman/api/path_utils.py        1970-01-01 
01:00:00.000000000 +0100
+++ new/podman-py-5.2.0/podman/api/path_utils.py        2024-08-02 
15:18:25.000000000 +0200
@@ -0,0 +1,46 @@
+"""Helper functions for managing paths"""
+
+import errno
+import getpass
+import os
+import stat
+
+
+def get_runtime_dir() -> str:
+    """Returns the runtime directory for the current user"""
+    try:
+        return os.environ['XDG_RUNTIME_DIR']
+    except KeyError:
+        user = getpass.getuser()
+        fallback = f'/tmp/podmanpy-runtime-dir-fallback-{user}'
+
+        try:
+            # This must be a real directory, not a symlink, so attackers can't
+            # point it elsewhere. So we use lstat to check it.
+            fallback_st = os.lstat(fallback)
+        except OSError as e:
+            if e.errno == errno.ENOENT:
+                os.mkdir(fallback, 0o700)
+            else:
+                raise
+        else:
+            # The fallback must be a directory
+            if not stat.S_ISDIR(fallback_st.st_mode):
+                os.unlink(fallback)
+                os.mkdir(fallback, 0o700)
+            # Must be owned by the user and not accessible by anyone else
+            elif (fallback_st.st_uid != os.getuid()) or (
+                fallback_st.st_mode & (stat.S_IRWXG | stat.S_IRWXO)
+            ):
+                os.rmdir(fallback)
+                os.mkdir(fallback, 0o700)
+
+        return fallback
+
+
+def get_xdg_config_home() -> str:
+    """Returns the XDG_CONFIG_HOME directory for the current user"""
+    try:
+        return os.environ["XDG_CONFIG_HOME"]
+    except KeyError:
+        return os.path.join(os.path.expanduser("~"), ".config")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/podman/api/ssh.py 
new/podman-py-5.2.0/podman/api/ssh.py
--- old/podman-py-5.0.0/podman/api/ssh.py       2024-03-22 22:46:27.000000000 
+0100
+++ new/podman-py-5.2.0/podman/api/ssh.py       2024-08-02 15:18:25.000000000 
+0200
@@ -15,12 +15,12 @@
 from typing import Optional, Union
 
 import time
-import xdg.BaseDirectory
 
 import urllib3
 import urllib3.connection
 
 from requests.adapters import DEFAULT_POOLBLOCK, DEFAULT_RETRIES, HTTPAdapter
+from podman.api.path_utils import get_runtime_dir
 
 from .adapter_utils import _key_normalizer
 
@@ -46,7 +46,7 @@
         self.identity = identity
         self._proc: Optional[subprocess.Popen] = None
 
-        runtime_dir = 
pathlib.Path(xdg.BaseDirectory.get_runtime_dir(strict=False)) / "podman"
+        runtime_dir = pathlib.Path(get_runtime_dir()) / "podman"
         runtime_dir.mkdir(mode=0o700, parents=True, exist_ok=True)
 
         self.local_sock = runtime_dir / 
f"podman-forward-{random.getrandbits(80):x}.sock"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/podman/client.py 
new/podman-py-5.2.0/podman/client.py
--- old/podman-py-5.0.0/podman/client.py        2024-03-22 22:46:27.000000000 
+0100
+++ new/podman-py-5.2.0/podman/client.py        2024-08-02 15:18:25.000000000 
+0200
@@ -6,10 +6,9 @@
 from pathlib import Path
 from typing import Any, Dict, Optional
 
-import xdg.BaseDirectory
-
 from podman.api import cached_property
 from podman.api.client import APIClient
+from podman.api.path_utils import get_runtime_dir
 from podman.domain.config import PodmanConfig
 from podman.domain.containers_manager import ContainersManager
 from podman.domain.events import EventsManager
@@ -70,9 +69,7 @@
             # Override configured identity, if provided in arguments
             api_kwargs["identity"] = kwargs.get("identity", 
str(connection.identity))
         elif "base_url" not in api_kwargs:
-            path = str(
-                Path(xdg.BaseDirectory.get_runtime_dir(strict=False)) / 
"podman" / "podman.sock"
-            )
+            path = str(Path(get_runtime_dir()) / "podman" / "podman.sock")
             api_kwargs["base_url"] = "http+unix://" + path
         self.api = APIClient(**api_kwargs)
 
@@ -141,7 +138,7 @@
     @cached_property
     def containers(self) -> ContainersManager:
         """Returns Manager for operations on containers stored by a Podman 
service."""
-        return ContainersManager(client=self.api)
+        return ContainersManager(client=self.api, podman_client=self)
 
     @cached_property
     def images(self) -> ImagesManager:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/podman/domain/config.py 
new/podman-py-5.2.0/podman/domain/config.py
--- old/podman-py-5.0.0/podman/domain/config.py 2024-03-22 22:46:27.000000000 
+0100
+++ new/podman-py-5.2.0/podman/domain/config.py 2024-08-02 15:18:25.000000000 
+0200
@@ -6,9 +6,8 @@
 from typing import Dict, Optional
 import json
 
-import xdg.BaseDirectory
-
 from podman.api import cached_property
+from podman.api.path_utils import get_xdg_config_home
 
 if sys.version_info >= (3, 11):
     from tomllib import loads as toml_loads
@@ -69,7 +68,7 @@
 
         self.is_default = False
         if path is None:
-            home = Path(xdg.BaseDirectory.xdg_config_home)
+            home = Path(get_xdg_config_home())
             self.path = home / "containers" / "podman-connections.json"
             old_toml_file = home / "containers" / "containers.conf"
             self.is_default = True
@@ -81,6 +80,7 @@
             self.is_default = True
         else:
             self.path = Path(path)
+            old_toml_file = None
 
         self.attrs = {}
         if self.path.exists():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/podman/domain/containers.py 
new/podman-py-5.2.0/podman/domain/containers.py
--- old/podman-py-5.0.0/podman/domain/containers.py     2024-03-22 
22:46:27.000000000 +0100
+++ new/podman-py-5.2.0/podman/domain/containers.py     2024-08-02 
15:18:25.000000000 +0200
@@ -9,6 +9,7 @@
 import requests
 
 from podman import api
+from podman.api.output_utils import demux_output
 from podman.domain.images import Image
 from podman.domain.images_manager import ImagesManager
 from podman.domain.manager import PodmanResource
@@ -164,8 +165,10 @@
             demux: Return stdout and stderr separately
 
         Returns:
-            First item is the command response code
-            Second item is the requests response content
+            First item is the command response code.
+            Second item is the requests response content.
+            If demux is True, the second item is a tuple of
+            (stdout, stderr).
 
         Raises:
             NotImplementedError: method not implemented.
@@ -199,6 +202,9 @@
         # get and return exec information
         response = self.client.get(f"/exec/{exec_id}/json")
         response.raise_for_status()
+        if demux:
+            stdout_data, stderr_data = demux_output(start_resp.content)
+            return response.json().get('ExitCode'), (stdout_data, stderr_data)
         return response.json().get('ExitCode'), start_resp.content
 
     def export(self, chunk_size: int = api.DEFAULT_CHUNK_SIZE) -> 
Iterator[bytes]:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/podman/domain/containers_create.py 
new/podman-py-5.2.0/podman/domain/containers_create.py
--- old/podman-py-5.0.0/podman/domain/containers_create.py      2024-03-22 
22:46:27.000000000 +0100
+++ new/podman-py-5.2.0/podman/domain/containers_create.py      2024-08-02 
15:18:25.000000000 +0200
@@ -460,7 +460,7 @@
             "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_option": pop("dns_opt"),
             "dns_search": pop("dns_search"),
             "dns_server": pop("dns"),
             "entrypoint": pop("entrypoint"),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/podman/domain/containers_manager.py 
new/podman-py-5.2.0/podman/domain/containers_manager.py
--- old/podman-py-5.0.0/podman/domain/containers_manager.py     2024-03-22 
22:46:27.000000000 +0100
+++ new/podman-py-5.2.0/podman/domain/containers_manager.py     2024-08-02 
15:18:25.000000000 +0200
@@ -30,7 +30,7 @@
         """Get container by name or id.
 
         Args:
-            container_id: Container name or id.
+            key: Container name or id.
 
         Returns:
             A `Container` object corresponding to `key`.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/podman/domain/containers_run.py 
new/podman-py-5.2.0/podman/domain/containers_run.py
--- old/podman-py-5.0.0/podman/domain/containers_run.py 2024-03-22 
22:46:27.000000000 +0100
+++ new/podman-py-5.2.0/podman/domain/containers_run.py 2024-08-02 
15:18:25.000000000 +0200
@@ -60,7 +60,7 @@
         try:
             container = self.create(image=image, command=command, **kwargs)
         except ImageNotFound:
-            self.client.images.pull(image, platform=kwargs.get("platform"))
+            self.podman_client.images.pull(image, 
platform=kwargs.get("platform"))
             container = self.create(image=image, command=command, **kwargs)
 
         container.start()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/podman/domain/images.py 
new/podman-py-5.2.0/podman/domain/images.py
--- old/podman-py-5.0.0/podman/domain/images.py 2024-03-22 22:46:27.000000000 
+0100
+++ new/podman-py-5.2.0/podman/domain/images.py 2024-08-02 15:18:25.000000000 
+0200
@@ -3,9 +3,11 @@
 import logging
 from typing import Any, Dict, Iterator, List, Optional, Union
 
+import urllib.parse
+
 from podman import api
 from podman.domain.manager import PodmanResource
-from podman.errors import ImageNotFound
+from podman.errors import ImageNotFound, InvalidArgument
 
 logger = logging.getLogger("podman.images")
 
@@ -68,7 +70,7 @@
     def save(
         self,
         chunk_size: Optional[int] = api.DEFAULT_CHUNK_SIZE,
-        named: Union[str, bool] = False,  # pylint: disable=unused-argument
+        named: Union[str, bool] = False,
     ) -> Iterator[bytes]:
         """Returns Image as tarball.
 
@@ -77,13 +79,28 @@
         Args:
             chunk_size: If None, data will be streamed in received buffer size.
                 If not None, data will be returned in sized buffers. Default: 
2MB
-            named: Ignored.
+            named (str or bool): If ``False`` (default), the tarball will not
+                retain repository and tag information for this image. If set
+                to ``True``, the first tag in the :py:attr:`~tags` list will
+                be used to identify the image. Alternatively, any element of
+                the :py:attr:`~tags` list can be used as an argument to use
+                that specific tag as the saved identifier.
 
         Raises:
-            APIError: when service returns an error
+            APIError: When service returns an error
+            InvalidArgument: When the provided Tag name is not valid for the 
image.
         """
+
+        img = self.id
+        if named:
+            img = urllib.parse.quote(self.tags[0] if self.tags else img)
+            if isinstance(named, str):
+                if named not in self.tags:
+                    raise InvalidArgument(f"'{named}' is not a valid tag for 
this image")
+                img = urllib.parse.quote(named)
+
         response = self.client.get(
-            f"/images/{self.id}/get", params={"format": ["docker-archive"]}, 
stream=True
+            f"/images/{img}/get", params={"format": ["docker-archive"]}, 
stream=True
         )
         response.raise_for_status(not_found=ImageNotFound)
         return response.iter_content(chunk_size=chunk_size)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/podman/domain/images_manager.py 
new/podman-py-5.2.0/podman/domain/images_manager.py
--- old/podman-py-5.0.0/podman/domain/images_manager.py 2024-03-22 
22:46:27.000000000 +0100
+++ new/podman-py-5.2.0/podman/domain/images_manager.py 2024-08-02 
15:18:25.000000000 +0200
@@ -158,17 +158,22 @@
         deleted: List[Dict[str, str]] = []
         error: List[str] = []
         reclaimed: int = 0
-        for element in response.json():
-            if "Err" in element and element["Err"] is not None:
-                error.append(element["Err"])
-            else:
-                reclaimed += element["Size"]
-                deleted.append(
-                    {
-                        "Deleted": element["Id"],
-                        "Untagged": "",
-                    }
-                )
+        # If the prune doesn't remove images, the API returns "null"
+        # and it's interpreted as None (NoneType)
+        # so the for loop throws "TypeError: 'NoneType' object is not 
iterable".
+        # The below if condition fixes this issue.
+        if response.json() is not None:
+            for element in response.json():
+                if "Err" in element and element["Err"] is not None:
+                    error.append(element["Err"])
+                else:
+                    reclaimed += element["Size"]
+                    deleted.append(
+                        {
+                            "Deleted": element["Id"],
+                            "Untagged": "",
+                        }
+                    )
         if len(error) > 0:
             raise APIError(response.url, response=response, explanation="; 
".join(error))
 
@@ -309,7 +314,8 @@
         else:
             params["reference"] = f"{repository}:{tag}"
 
-        if "platform" in kwargs:
+        # Check if "platform" in kwargs AND it has value.
+        if "platform" in kwargs and kwargs["platform"]:
             tokens = kwargs.get("platform").split("/")
             if 1 < len(tokens) > 3:
                 raise ValueError(f'\'{kwargs.get("platform")}\' is not a legal 
platform.')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/podman/domain/manager.py 
new/podman-py-5.2.0/podman/domain/manager.py
--- old/podman-py-5.0.0/podman/domain/manager.py        2024-03-22 
22:46:27.000000000 +0100
+++ new/podman-py-5.2.0/podman/domain/manager.py        2024-08-02 
15:18:25.000000000 +0200
@@ -22,6 +22,7 @@
         attrs: Optional[Mapping[str, Any]] = None,
         client: Optional[APIClient] = None,
         collection: Optional["Manager"] = None,
+        podman_client: Optional["PodmanClient"] = None,
     ):
         """Initialize base class for PodmanResource's.
 
@@ -29,10 +30,12 @@
             attrs: Mapping of attributes for resource from Podman service.
             client: Configured connection to a Podman service.
             collection: Manager of this category of resource, named 
`collection` for compatibility
+            podman_client: PodmanClient() configured to connect to Podman 
object.
         """
         super().__init__()
         self.client = client
         self.manager = collection
+        self.podman_client = podman_client
 
         self.attrs = {}
         if attrs is not None:
@@ -77,14 +80,18 @@
     def resource(self):
         """Type[PodmanResource]: Class which the factory method 
prepare_model() will use."""
 
-    def __init__(self, client: APIClient = None) -> None:
+    def __init__(
+        self, client: Optional[APIClient] = None, podman_client: 
Optional["PodmanClient"] = None
+    ) -> None:
         """Initialize Manager() object.
 
         Args:
             client: APIClient() configured to connect to Podman service.
+            podman_client: PodmanClient() configured to connect to Podman 
object.
         """
         super().__init__()
         self.client = client
+        self.podman_client = podman_client
 
     @abstractmethod
     def exists(self, key: str) -> bool:
@@ -110,6 +117,7 @@
         # Refresh existing PodmanResource.
         if isinstance(attrs, PodmanResource):
             attrs.client = self.client
+            attrs.podman_client = self.podman_client
             attrs.collection = self
             return attrs
 
@@ -117,7 +125,9 @@
         if isinstance(attrs, abc.Mapping):
             # TODO Determine why pylint is reporting typing.Type not callable
             # pylint: disable=not-callable
-            return self.resource(attrs=attrs, client=self.client, 
collection=self)
+            return self.resource(
+                attrs=attrs, client=self.client, 
podman_client=self.podman_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-5.0.0/podman/tests/__init__.py 
new/podman-py-5.2.0/podman/tests/__init__.py
--- old/podman-py-5.0.0/podman/tests/__init__.py        2024-03-22 
22:46:27.000000000 +0100
+++ new/podman-py-5.2.0/podman/tests/__init__.py        2024-08-02 
15:18:25.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/v5.0.0/libpod";
+LIBPOD_URL = "http://%2Frun%2Fapi.sock/v5.2.0/libpod";
 COMPATIBLE_URL = "http://%2Frun%2Fapi.sock/v1.40";
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/podman-py-5.0.0/podman/tests/integration/test_container_exec.py 
new/podman-py-5.2.0/podman/tests/integration/test_container_exec.py
--- old/podman-py-5.0.0/podman/tests/integration/test_container_exec.py 
1970-01-01 01:00:00.000000000 +0100
+++ new/podman-py-5.2.0/podman/tests/integration/test_container_exec.py 
2024-08-02 15:18:25.000000000 +0200
@@ -0,0 +1,53 @@
+import unittest
+
+import podman.tests.integration.base as base
+from podman import PodmanClient
+
+# @unittest.skipIf(os.geteuid() != 0, 'Skipping, not running as root')
+
+
+class ContainersExecIntegrationTests(base.IntegrationTest):
+    """Containers integration tests for exec"""
+
+    def setUp(self):
+        super().setUp()
+
+        self.client = PodmanClient(base_url=self.socket_uri)
+        self.addCleanup(self.client.close)
+
+        self.alpine_image = self.client.images.pull("quay.io/libpod/alpine", 
tag="latest")
+        self.containers = []
+
+    def tearDown(self):
+        for container in self.containers:
+            container.remove(force=True)
+
+    def test_container_exec_run(self):
+        """Test any command that will return code 0 and no output"""
+        container = self.client.containers.create(self.alpine_image, 
command=["top"], detach=True)
+        container.start()
+        error_code, stdout = container.exec_run("echo hello")
+
+        self.assertEqual(error_code, 0)
+        self.assertEqual(stdout, b'\x01\x00\x00\x00\x00\x00\x00\x06hello\n')
+
+    def test_container_exec_run_errorcode(self):
+        """Test a failing command with stdout and stderr in a single 
bytestring"""
+        container = self.client.containers.create(self.alpine_image, 
command=["top"], detach=True)
+        container.start()
+        error_code, output = container.exec_run("ls nonexistent")
+
+        self.assertEqual(error_code, 1)
+        self.assertEqual(
+            output, b"\x02\x00\x00\x00\x00\x00\x00+ls: nonexistent: No such 
file or directory\n"
+        )
+
+    def test_container_exec_run_demux(self):
+        """Test a failing command with stdout and stderr in a bytestring 
tuple"""
+        container = self.client.containers.create(self.alpine_image, 
command=["top"], detach=True)
+        container.start()
+        error_code, output = container.exec_run("ls nonexistent", demux=True)
+
+        self.assertEqual(error_code, 1)
+        self.assertEqual(output[0], b'')
+        self.assertEqual(output[1], b"ls: nonexistent: No such file or 
directory\n")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/podman-py-5.0.0/podman/tests/integration/test_images.py 
new/podman-py-5.2.0/podman/tests/integration/test_images.py
--- old/podman-py-5.0.0/podman/tests/integration/test_images.py 2024-03-22 
22:46:27.000000000 +0100
+++ new/podman-py-5.2.0/podman/tests/integration/test_images.py 2024-08-02 
15:18:25.000000000 +0200
@@ -109,6 +109,25 @@
             self.assertIn(image.id, deleted)
             self.assertGreater(actual["SpaceReclaimed"], 0)
 
+        with self.subTest("Export Image to tarball (in memory) with named 
mode"):
+            alpine_image = self.client.images.pull("quay.io/libpod/alpine", 
tag="latest")
+            image_buffer = io.BytesIO()
+            for chunk in alpine_image.save(named=True):
+                image_buffer.write(chunk)
+            image_buffer.seek(0, 0)
+
+            with tarfile.open(fileobj=image_buffer, mode="r") as tar:
+                items_in_tar = tar.getnames()
+                # Check if repositories file is available in the tarball
+                self.assertIn("repositories", items_in_tar)
+                # Extract the 'repositories' file
+                repositories_file = tar.extractfile("repositories")
+                if repositories_file is not None:
+                    # Check the content of the "repositories" file.
+                    repositories_content = 
repositories_file.read().decode("utf-8")
+                    # Check if "repositories" file contains the name of the 
Image (named).
+                    self.assertTrue("alpine" in str(repositories_content))
+
     def test_search(self):
         actual = self.client.images.search("alpine", filters={"is-official": 
True})
         self.assertEqual(len(actual), 1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/podman-py-5.0.0/podman/tests/unit/test_imagesmanager.py 
new/podman-py-5.2.0/podman/tests/unit/test_imagesmanager.py
--- old/podman-py-5.0.0/podman/tests/unit/test_imagesmanager.py 2024-03-22 
22:46:27.000000000 +0100
+++ new/podman-py-5.2.0/podman/tests/unit/test_imagesmanager.py 2024-08-02 
15:18:25.000000000 +0200
@@ -224,6 +224,15 @@
         self.assertEqual(e.exception.explanation, "Test prune failure in 
response body.")
 
     @requests_mock.Mocker()
+    def test_prune_empty(self, mock):
+        """Unit test if prune API responses null (None)."""
+        mock.post(tests.LIBPOD_URL + "/images/prune", text="null")
+
+        report = self.client.images.prune()
+        self.assertEqual(report["ImagesDeleted"], [])
+        self.assertEqual(report["SpaceReclaimed"], 0)
+
+    @requests_mock.Mocker()
     def test_get(self, mock):
         mock.get(
             tests.LIBPOD_URL + "/images/fedora%3Alatest/json",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/podman-py-5.0.0/podman/tests/unit/test_podmanclient.py 
new/podman-py-5.2.0/podman/tests/unit/test_podmanclient.py
--- old/podman-py-5.0.0/podman/tests/unit/test_podmanclient.py  2024-03-22 
22:46:27.000000000 +0100
+++ new/podman-py-5.2.0/podman/tests/unit/test_podmanclient.py  2024-08-02 
15:18:25.000000000 +0200
@@ -5,9 +5,9 @@
 from unittest.mock import MagicMock
 
 import requests_mock
-import xdg
 
 from podman import PodmanClient, tests
+from podman.api.path_utils import get_runtime_dir, get_xdg_config_home
 
 
 class PodmanClientTestCase(unittest.TestCase):
@@ -88,7 +88,7 @@
                 )
 
             # Build path to support tests running as root or a user
-            expected = Path(xdg.BaseDirectory.xdg_config_home) / "containers" 
/ "containers.conf"
+            expected = Path(get_xdg_config_home()) / "containers" / 
"containers.conf"
             PodmanClientTestCase.opener.assert_called_with(expected, 
encoding="utf-8")
 
     def test_connect_404(self):
@@ -100,16 +100,12 @@
         with mock.patch.multiple(Path, open=self.mocked_open, 
exists=MagicMock(return_value=True)):
             with PodmanClient() as client:
                 expected = "http+unix://" + urllib.parse.quote_plus(
-                    str(
-                        Path(xdg.BaseDirectory.get_runtime_dir(strict=False))
-                        / "podman"
-                        / "podman.sock"
-                    )
+                    str(Path(get_runtime_dir()) / "podman" / "podman.sock")
                 )
                 self.assertEqual(client.api.base_url.geturl(), expected)
 
             # Build path to support tests running as root or a user
-            expected = Path(xdg.BaseDirectory.xdg_config_home) / "containers" 
/ "containers.conf"
+            expected = Path(get_xdg_config_home()) / "containers" / 
"containers.conf"
             PodmanClientTestCase.opener.assert_called_with(expected, 
encoding="utf-8")
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/podman/version.py 
new/podman-py-5.2.0/podman/version.py
--- old/podman-py-5.0.0/podman/version.py       2024-03-22 22:46:27.000000000 
+0100
+++ new/podman-py-5.2.0/podman/version.py       2024-08-02 15:18:25.000000000 
+0200
@@ -1,4 +1,4 @@
 """Version of PodmanPy."""
 
-__version__ = "5.0.0"
+__version__ = "5.2.0"
 __compatible_version__ = "1.40"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/requirements.txt 
new/podman-py-5.2.0/requirements.txt
--- old/podman-py-5.0.0/requirements.txt        2024-03-22 22:46:27.000000000 
+0100
+++ new/podman-py-5.2.0/requirements.txt        2024-08-02 15:18:25.000000000 
+0200
@@ -1,5 +1,4 @@
 # Any changes should be copied into pyproject.toml
-pyxdg>=0.26
 requests>=2.24
 setuptools
 sphinx
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/setup.cfg 
new/podman-py-5.2.0/setup.cfg
--- old/podman-py-5.0.0/setup.cfg       2024-03-22 22:46:27.000000000 +0100
+++ new/podman-py-5.2.0/setup.cfg       2024-08-02 15:18:25.000000000 +0200
@@ -1,7 +1,7 @@
 [metadata]
 name = podman
-version = 5.0.0
-author = Brent Baude, Jhon Honce, Urvashi Mohnani
+version = 5.2.0
+author = Brent Baude, Jhon Honce, Urvashi Mohnani, Nicola Sella
 author_email = jho...@redhat.com
 description = Bindings for Podman RESTful API
 long_description = file: README.md
@@ -25,6 +25,7 @@
     Programming Language :: Python :: 3.9
     Programming Language :: Python :: 3.10
     Programming Language :: Python :: 3.11
+    Programming Language :: Python :: 3.12
     Topic :: Software Development :: Libraries :: Python Modules
 keywords = podman, libpod
 
@@ -34,7 +35,6 @@
 test_suite =
 # Any changes should be copied into pyproject.toml
 install_requires =
-    pyxdg >=0.26
     requests >=2.24
     tomli>=1.2.3; python_version<'3.11'
     urllib3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/podman-py-5.0.0/tox.ini new/podman-py-5.2.0/tox.ini
--- old/podman-py-5.0.0/tox.ini 2024-03-22 22:46:27.000000000 +0100
+++ new/podman-py-5.2.0/tox.ini 2024-08-02 15:18:25.000000000 +0200
@@ -1,6 +1,6 @@
 [tox]
 minversion = 3.2.0
-envlist = pylint,coverage,py36,py38,py39,py310,py311
+envlist = pylint,coverage,py36,py38,py39,py310,py311,py312
 ignore_basepython_conflict = true
 
 [testenv]

Reply via email to