Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-swiftclient for openSUSE:Factory checked in at 2024-06-05 17:42:10
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-swiftclient (Old)
and /work/SRC/openSUSE:Factory/.python-swiftclient.new.24587 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-swiftclient"
Wed Jun 5 17:42:10 2024 rev:35 rq:1178611 version:4.6.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-swiftclient/python-swiftclient.changes 2024-01-15 22:19:28.383382146 +0100
+++ /work/SRC/openSUSE:Factory/.python-swiftclient.new.24587/python-swiftclient.changes 2024-06-05 17:42:48.134983980 +0200
@@ -1,0 +2,27 @@
+Tue Jun 4 20:08:29 UTC 2024 - cloud-devel@suse.de
+
+- update to version 4.6.0
+ - make setup dependencies discoverable
+ - tests: Fix call assertion
+ - Fix swiftclient output regression
+ - Add transaction id to errors
+ - reno: Update master for unmaintained/zed
+ - reno: Update master for unmaintained/victoria
+ - CI: constrain deps for tests
+ - Mark py312 job as voting and update classifiers
+ - Update master for stable/2023.2
+ - CI: skip func tests on irrelevant changes
+ - CI: add py39 and py310 to experimental pipeline
+ - Bring back (experimental) py38 job
+ - tests: Skip keystoneauth tests if not available
+ - Update master for stable/2024.1
+ - shell: Print friendly account byte quotas
+ - Authors / changelog for 4.5.0
+ - reno: Update master for unmaintained/yoga
+ - lint: Up-rev hacking
+ - CI: Fix py36 and py37 jobs
+ - Remove duplicate script entry leading to broken wheel build
+ - reno: Update master for unmaintained/xena
+ - reno: Update master for unmaintained/wallaby
+
+-------------------------------------------------------------------
Old:
----
python-swiftclient-4.4.0.tar.gz
New:
----
python-swiftclient-4.6.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-swiftclient.spec ++++++
--- /var/tmp/diff_new_pack.SzPt7N/_old 2024-06-05 17:42:50.543071676 +0200
+++ /var/tmp/diff_new_pack.SzPt7N/_new 2024-06-05 17:42:50.547071823 +0200
@@ -17,13 +17,13 @@
Name: python-swiftclient
-Version: 4.4.0
+Version: 4.6.0
Release: 0
Summary: OpenStack Object Storage API Client Library
License: Apache-2.0
Group: Development/Languages/Python
URL: https://docs.openstack.org/python-swiftclient
-Source0: https://files.pythonhosted.org/packages/source/p/python-swiftclient/python-s...
+Source0: https://files.pythonhosted.org/packages/source/p/python-swiftclient/python-s...
BuildRequires: openstack-macros
BuildRequires: python3-keystoneclient
BuildRequires: python3-pbr
@@ -37,7 +37,7 @@
%package -n python3-swiftclient
Summary: OpenStack Object Storage API Client Library
-Requires: python3-requests >= 1.1.0
+Requires: python3-requests >= 2.4.0
%if 0%{?suse_version}
Obsoletes: python2-swiftclient < 3.9.0
%endif
@@ -61,7 +61,7 @@
This package contains documentation files for %{name}.
%prep
-%autosetup -p1 -n python-swiftclient-4.4.0
+%autosetup -p1 -n python-swiftclient-4.6.0
%py_req_cleanup
%build
++++++ _service ++++++
--- /var/tmp/diff_new_pack.SzPt7N/_old 2024-06-05 17:42:50.591073424 +0200
+++ /var/tmp/diff_new_pack.SzPt7N/_new 2024-06-05 17:42:50.595073571 +0200
@@ -2,7 +2,7 @@
<service mode="manual" name="renderspec">
<param name="input-template">https://opendev.org/openstack/rpm-packaging/raw/master/openstack/python-swif...</param>
<param name="output-name">python-swiftclient.spec</param>
- <param name="requirements">https://opendev.org/openstack/python-swiftclient/raw/branch/stable/xena/requ...</param>
+ <param name="requirements">https://opendev.org/openstack/python-swiftclient/raw/master/requirements.txt</param>
<param name="changelog-email">cloud-devel@suse.de</param>
<param name="changelog-provider">gh,openstack,python-swiftclient</param>
</service>
++++++ python-swiftclient-4.4.0.tar.gz -> python-swiftclient-4.6.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/.mailmap new/python-swiftclient-4.6.0/.mailmap
--- old/python-swiftclient-4.4.0/.mailmap 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/.mailmap 2024-05-23 10:01:23.000000000 +0200
@@ -97,3 +97,4 @@
Flavio Percoco
Timur Alperovich
Thiago da Silva
+DavHau
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/.zuul.yaml new/python-swiftclient-4.6.0/.zuul.yaml
--- old/python-swiftclient-4.4.0/.zuul.yaml 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/.zuul.yaml 2024-05-23 10:01:23.000000000 +0200
@@ -37,21 +37,33 @@
- publish-openstack-docs-pti
- release-notes-jobs-python3
experimental:
- # on-demand pipeline used to test older (but still supported) versions of python
+ # on-demand pipeline used to test older (but still supported) versions of python,
+ # as well as intermediate releases that the openstack-python3-jobs might skip
jobs:
- openstack-tox-py36
- openstack-tox-py37
+ - openstack-tox-py38
+ - openstack-tox-py310
check:
jobs:
- - swiftclient-swift-functional
- - swiftclient-functional
- - openstack-tox-py311:
+ - swiftclient-functional:
+ irrelevant-files: &functest-irrelevant-files
+ - ^(doc|releasenotes)/.*$
+ - ^test/unit/.*$
+ - ^(.gitreview|.mailmap|AUTHORS|ChangeLog|.*\.rst)$
+ - swiftclient-swift-functional:
+ irrelevant-files: *functest-irrelevant-files
+ - tempest-full-py3:
+ irrelevant-files: *functest-irrelevant-files
+ - openstack-tox-py311
+ - openstack-tox-py312:
voting: true
gate:
jobs:
- swiftclient-swift-functional
- swiftclient-functional
- - openstack-tox-py311:
+ - openstack-tox-py311
+ - openstack-tox-py312:
voting: true
post:
jobs:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/AUTHORS new/python-swiftclient-4.6.0/AUTHORS
--- old/python-swiftclient-4.4.0/AUTHORS 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/AUTHORS 2024-05-23 10:01:23.000000000 +0200
@@ -30,6 +30,7 @@
Dan Prince (dprince@redhat.com)
Daniel Wakefield (daniel.wakefield@hp.com)
Darrell Bishop (darrell@swiftstack.com)
+DavHau (hsngrmpf@gmail.com)
David Goetz (david.goetz@rackspace.com)
David Kranz (david.kranz@qrclab.com)
David Shrewsbury (shrewsbury.dave@gmail.com)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/ChangeLog new/python-swiftclient-4.6.0/ChangeLog
--- old/python-swiftclient-4.4.0/ChangeLog 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/ChangeLog 2024-05-23 10:01:23.000000000 +0200
@@ -1,3 +1,15 @@
+4.5.0
+-----
+
+* `swift stat --lh` now prints account quotas (including per-policy quotas)
+ in human-readable units, similar to account usage values.
+
+* Modernized some aspects of packaging, allowing wheels to be built with more
+ (and more recent) tools.
+
+* Various other minor bug fixes and improvements.
+
+
4.4.0
-----
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/PKG-INFO new/python-swiftclient-4.6.0/PKG-INFO
--- old/python-swiftclient-4.4.0/PKG-INFO 2023-09-01 15:39:15.668769100 +0200
+++ new/python-swiftclient-4.6.0/PKG-INFO 2024-05-23 10:01:55.497597500 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: python-swiftclient
-Version: 4.4.0
+Version: 4.6.0
Summary: OpenStack Object Storage API Client Library
Home-page: https://docs.openstack.org/python-swiftclient/latest/
Author: OpenStack
@@ -76,6 +76,7 @@
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3 :: Only
Requires-Python: >=3.6
Description-Content-Type: text/x-rst
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/pyproject.toml new/python-swiftclient-4.6.0/pyproject.toml
--- old/python-swiftclient-4.4.0/pyproject.toml 1970-01-01 01:00:00.000000000 +0100
+++ new/python-swiftclient-4.6.0/pyproject.toml 2024-05-23 10:01:23.000000000 +0200
@@ -0,0 +1,3 @@
+[build-system]
+requires = ["setuptools", "pbr"]
+build-backend = "setuptools.build_meta"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/python_swiftclient.egg-info/PKG-INFO new/python-swiftclient-4.6.0/python_swiftclient.egg-info/PKG-INFO
--- old/python-swiftclient-4.4.0/python_swiftclient.egg-info/PKG-INFO 2023-09-01 15:39:15.000000000 +0200
+++ new/python-swiftclient-4.6.0/python_swiftclient.egg-info/PKG-INFO 2024-05-23 10:01:55.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: python-swiftclient
-Version: 4.4.0
+Version: 4.6.0
Summary: OpenStack Object Storage API Client Library
Home-page: https://docs.openstack.org/python-swiftclient/latest/
Author: OpenStack
@@ -76,6 +76,7 @@
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3 :: Only
Requires-Python: >=3.6
Description-Content-Type: text/x-rst
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/python_swiftclient.egg-info/SOURCES.txt new/python-swiftclient-4.6.0/python_swiftclient.egg-info/SOURCES.txt
--- old/python-swiftclient-4.4.0/python_swiftclient.egg-info/SOURCES.txt 2023-09-01 15:39:15.000000000 +0200
+++ new/python-swiftclient-4.6.0/python_swiftclient.egg-info/SOURCES.txt 2024-05-23 10:01:55.000000000 +0200
@@ -11,6 +11,7 @@
LICENSE
MANIFEST.in
README.rst
+pyproject.toml
requirements.txt
run_tests.sh
setup.cfg
@@ -58,7 +59,10 @@
releasenotes/notes/3_9_0_release-3c293d277f14ec22.yaml
releasenotes/notes/4_3_0_release.yaml
releasenotes/notes/4_4_0_release-d731bab5982c160b.yaml
+releasenotes/notes/4_5_0_release-b315d25b889293f2.yaml
releasenotes/source/2023.1.rst
+releasenotes/source/2023.2.rst
+releasenotes/source/2024.1.rst
releasenotes/source/conf.py
releasenotes/source/current.rst
releasenotes/source/index.rst
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/python_swiftclient.egg-info/pbr.json new/python-swiftclient-4.6.0/python_swiftclient.egg-info/pbr.json
--- old/python-swiftclient-4.4.0/python_swiftclient.egg-info/pbr.json 2023-09-01 15:39:15.000000000 +0200
+++ new/python-swiftclient-4.6.0/python_swiftclient.egg-info/pbr.json 2024-05-23 10:01:55.000000000 +0200
@@ -1 +1 @@
-{"git_version": "54fbfa8", "is_release": true}
\ No newline at end of file
+{"git_version": "e7061db", "is_release": true}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/python_swiftclient.egg-info/requires.txt new/python-swiftclient-4.6.0/python_swiftclient.egg-info/requires.txt
--- old/python-swiftclient-4.4.0/python_swiftclient.egg-info/requires.txt 2023-09-01 15:39:15.000000000 +0200
+++ new/python-swiftclient-4.6.0/python_swiftclient.egg-info/requires.txt 2024-05-23 10:01:55.000000000 +0200
@@ -5,7 +5,8 @@
[test]
coverage!=4.4,>=4.0
-hacking<3.3.0,>=3.2.0
+hacking<6.2.0,>=3.2.0
keystoneauth1>=3.4.0
openstacksdk>=0.11.0
+python-keystoneclient>=0.7.0
stestr!=3.0.0,>=2.0.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/releasenotes/notes/4_5_0_release-b315d25b889293f2.yaml new/python-swiftclient-4.6.0/releasenotes/notes/4_5_0_release-b315d25b889293f2.yaml
--- old/python-swiftclient-4.4.0/releasenotes/notes/4_5_0_release-b315d25b889293f2.yaml 1970-01-01 01:00:00.000000000 +0100
+++ new/python-swiftclient-4.6.0/releasenotes/notes/4_5_0_release-b315d25b889293f2.yaml 2024-05-23 10:01:23.000000000 +0200
@@ -0,0 +1,12 @@
+---
+features:
+ - |
+ ``swift stat --lh`` now prints account quotas (including per-policy quotas)
+ in human-readable units, similar to account usage values.
+
+ - |
+ Modernized some aspects of packaging, allowing wheels to be built with more
+ (and more recent) tools.
+fixes:
+ - |
+ Various other minor bug fixes and improvements.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/releasenotes/source/2023.2.rst new/python-swiftclient-4.6.0/releasenotes/source/2023.2.rst
--- old/python-swiftclient-4.4.0/releasenotes/source/2023.2.rst 1970-01-01 01:00:00.000000000 +0100
+++ new/python-swiftclient-4.6.0/releasenotes/source/2023.2.rst 2024-05-23 10:01:23.000000000 +0200
@@ -0,0 +1,6 @@
+===========================
+2023.2 Series Release Notes
+===========================
+
+.. release-notes::
+ :branch: stable/2023.2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/releasenotes/source/2024.1.rst new/python-swiftclient-4.6.0/releasenotes/source/2024.1.rst
--- old/python-swiftclient-4.4.0/releasenotes/source/2024.1.rst 1970-01-01 01:00:00.000000000 +0100
+++ new/python-swiftclient-4.6.0/releasenotes/source/2024.1.rst 2024-05-23 10:01:23.000000000 +0200
@@ -0,0 +1,6 @@
+===========================
+2024.1 Series Release Notes
+===========================
+
+.. release-notes::
+ :branch: stable/2024.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/releasenotes/source/index.rst new/python-swiftclient-4.6.0/releasenotes/source/index.rst
--- old/python-swiftclient-4.4.0/releasenotes/source/index.rst 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/releasenotes/source/index.rst 2024-05-23 10:01:23.000000000 +0200
@@ -6,6 +6,8 @@
:maxdepth: 1
current
+ 2024.1
+ 2023.2
2023.1
zed
yoga
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/releasenotes/source/victoria.rst new/python-swiftclient-4.6.0/releasenotes/source/victoria.rst
--- old/python-swiftclient-4.4.0/releasenotes/source/victoria.rst 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/releasenotes/source/victoria.rst 2024-05-23 10:01:23.000000000 +0200
@@ -3,4 +3,4 @@
=============================
.. release-notes::
- :branch: stable/victoria
+ :branch: unmaintained/victoria
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/releasenotes/source/wallaby.rst new/python-swiftclient-4.6.0/releasenotes/source/wallaby.rst
--- old/python-swiftclient-4.4.0/releasenotes/source/wallaby.rst 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/releasenotes/source/wallaby.rst 2024-05-23 10:01:23.000000000 +0200
@@ -3,4 +3,4 @@
============================
.. release-notes::
- :branch: stable/wallaby
+ :branch: unmaintained/wallaby
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/releasenotes/source/xena.rst new/python-swiftclient-4.6.0/releasenotes/source/xena.rst
--- old/python-swiftclient-4.4.0/releasenotes/source/xena.rst 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/releasenotes/source/xena.rst 2024-05-23 10:01:23.000000000 +0200
@@ -3,4 +3,4 @@
=========================
.. release-notes::
- :branch: stable/xena
+ :branch: unmaintained/xena
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/releasenotes/source/yoga.rst new/python-swiftclient-4.6.0/releasenotes/source/yoga.rst
--- old/python-swiftclient-4.4.0/releasenotes/source/yoga.rst 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/releasenotes/source/yoga.rst 2024-05-23 10:01:23.000000000 +0200
@@ -3,4 +3,4 @@
=========================
.. release-notes::
- :branch: stable/yoga
+ :branch: unmaintained/yoga
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/releasenotes/source/zed.rst new/python-swiftclient-4.6.0/releasenotes/source/zed.rst
--- old/python-swiftclient-4.4.0/releasenotes/source/zed.rst 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/releasenotes/source/zed.rst 2024-05-23 10:01:23.000000000 +0200
@@ -3,4 +3,4 @@
========================
.. release-notes::
- :branch: stable/zed
+ :branch: unmaintained/zed
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/setup.cfg new/python-swiftclient-4.6.0/setup.cfg
--- old/python-swiftclient-4.4.0/setup.cfg 2023-09-01 15:39:15.668769100 +0200
+++ new/python-swiftclient-4.6.0/setup.cfg 2024-05-23 10:01:55.497597500 +0200
@@ -29,13 +29,12 @@
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
+ Programming Language :: Python :: 3.12
Programming Language :: Python :: 3 :: Only
[files]
packages =
swiftclient
-scripts =
- bin/swift
data_files =
share/man/man1 = doc/manpages/swift.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/swiftclient/client.py new/python-swiftclient-4.6.0/swiftclient/client.py
--- old/python-swiftclient-4.4.0/swiftclient/client.py 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/swiftclient/client.py 2024-05-23 10:01:23.000000000 +0200
@@ -19,10 +19,13 @@
import socket
import re
import logging
+from urllib3.exceptions import HTTPError as urllib_http_error
+
import warnings
from requests.exceptions import RequestException, SSLError
import http.client as http_client
+from requests.structures import CaseInsensitiveDict
from urllib.parse import quote, unquote
from urllib.parse import urljoin, urlparse, urlunparse
from time import sleep, time
@@ -209,6 +212,15 @@
return ret
+class LowerKeyCaseInsensitiveDict(CaseInsensitiveDict):
+ """
+ CaseInsensitiveDict returning lower case keys for items()
+ """
+
+ def __iter__(self):
+ return iter(self._store.keys())
+
+
class _ObjectBody:
"""
Readable and iterable object body response wrapper.
@@ -287,7 +299,7 @@
try:
buf = self.resp.read(length)
self.bytes_read += len(buf)
- except (socket.error, RequestException):
+ except (socket.error, urllib_http_error, RequestException):
if self.conn.attempts > self.conn.retries:
raise
if (not buf and self.bytes_read < self.expected_length and
@@ -735,9 +747,9 @@
def resp_header_dict(resp):
- resp_headers = {}
+ resp_headers = LowerKeyCaseInsensitiveDict()
for header, value in resp.getheaders():
- header = parse_header_string(header).lower()
+ header = parse_header_string(header)
resp_headers[header] = parse_header_string(value)
return resp_headers
@@ -1926,6 +1938,7 @@
is_not_range_request and resp_chunk_size and
self.attempts <= self.retries and
rheaders.get('transfer-encoding') is None)
+
if retry_is_possible:
body = _RetryBody(body.resp, self, container, obj,
resp_chunk_size=resp_chunk_size,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/swiftclient/command_helpers.py new/python-swiftclient-4.6.0/swiftclient/command_helpers.py
--- old/python-swiftclient-4.4.0/swiftclient/command_helpers.py 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/swiftclient/command_helpers.py 2024-05-23 10:01:23.000000000 +0200
@@ -15,6 +15,7 @@
POLICY_HEADER_PREFIX = 'x-account-storage-policy-'
+PER_POLICY_QUOTA_HEADER_PREFIX = 'x-account-quota-bytes-policy-'
def stat_account(conn, options):
@@ -38,6 +39,10 @@
('Objects', object_count),
('Bytes', bytes_used),
])
+ if headers.get('x-account-meta-quota-bytes'):
+ quota_bytes = prt_bytes(headers.get('x-account-meta-quota-bytes'),
+ options['human']).lstrip()
+ items.append(('Quota Bytes', quota_bytes))
policies = set()
for header_key, header_value in headers.items():
@@ -68,6 +73,10 @@
options['human']
).lstrip()),
))
+ policy_quota = headers.get(PER_POLICY_QUOTA_HEADER_PREFIX + policy)
+ if policy_quota:
+ items.append(('Quota Bytes for policy "' + policy + '"',
+ prt_bytes(policy_quota, options['human']).lstrip()))
return items, headers
@@ -75,7 +84,10 @@
def print_account_stats(items, headers, output_manager):
exclude_policy_headers = []
for header_key, header_value in headers.items():
- if header_key.lower().startswith(POLICY_HEADER_PREFIX):
+ if header_key.lower().startswith((
+ POLICY_HEADER_PREFIX,
+ PER_POLICY_QUOTA_HEADER_PREFIX,
+ )):
exclude_policy_headers.append(header_key)
items.extend(headers_to_items(
@@ -84,7 +96,8 @@
'content-length', 'date',
'x-account-container-count',
'x-account-object-count',
- 'x-account-bytes-used'] + exclude_policy_headers)))
+ 'x-account-bytes-used',
+ 'x-account-meta-quota-bytes'] + exclude_policy_headers)))
# line up the items nicely
offset = max(len(item) for item, value in items)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/swiftclient/multithreading.py new/python-swiftclient-4.6.0/swiftclient/multithreading.py
--- old/python-swiftclient-4.4.0/swiftclient/multithreading.py 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/swiftclient/multithreading.py 2024-05-23 10:01:23.000000000 +0200
@@ -89,6 +89,10 @@
msg = msg % fmt_args
self.error_print_pool.submit(self._print_error, msg)
+ def error_with_txn_id(self, swift_err):
+ self.error("{}\nFailed Transaction ID: {}".format(
+ swift_err.value, swift_err.transaction_id or 'unknown'))
+
def get_error_count(self):
return self.error_count
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/swiftclient/service.py new/python-swiftclient-4.6.0/swiftclient/service.py
--- old/python-swiftclient-4.4.0/swiftclient/service.py 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/swiftclient/service.py 2024-05-23 10:01:23.000000000 +0200
@@ -32,6 +32,9 @@
from threading import Thread
from queue import Queue
from queue import Empty as QueueEmpty
+from requests.exceptions import RequestException
+from socket import error as socket_error
+from urllib3.exceptions import HTTPError as urllib_http_error
from urllib.parse import quote
import json
@@ -68,12 +71,16 @@
class SwiftError(Exception):
def __init__(self, value, container=None, obj=None,
- segment=None, exc=None):
+ segment=None, exc=None, transaction_id=None):
self.value = value
self.container = container
self.obj = obj
self.segment = segment
self.exception = exc
+ if transaction_id is None:
+ self.transaction_id = getattr(exc, 'transaction_id', None)
+ else:
+ self.transaction_id = transaction_id
def __str__(self):
value = repr(self.value)
@@ -459,7 +466,9 @@
try:
self._content_length = int(headers.get('content-length'))
except ValueError:
- raise SwiftError('content-length header must be an integer')
+ raise SwiftError(
+ 'content-length header must be an integer',
+ transaction_id=self._txn_id)
def __iter__(self):
for chunk in self._body:
@@ -1306,9 +1315,15 @@
else:
pseudodir = True
- for chunk in obj_body:
- if fp is not None:
- fp.write(chunk)
+ try:
+ for chunk in obj_body:
+ if fp is not None:
+ fp.write(chunk)
+ except (socket_error,
+ urllib_http_error,
+ RequestException) as err:
+ raise ClientException(
+ str(err), http_response_headers=headers)
finish_time = time()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/swiftclient/shell.py new/python-swiftclient-4.6.0/swiftclient/shell.py
--- old/python-swiftclient-4.4.0/swiftclient/shell.py 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/swiftclient/shell.py 2024-05-23 10:01:23.000000000 +0200
@@ -227,7 +227,7 @@
output_manager.error('Error Deleting: {0}: {1}'
.format(p, r['error']))
except SwiftError as err:
- output_manager.error(err.value)
+ output_manager.error_with_txn_id(err)
st_download_options = '''[--all] [--marker <marker>] [--prefix <prefix>]
@@ -484,11 +484,13 @@
"Object '%s/%s' not found", container, obj)
continue
output_manager.error(
- "Error downloading object '%s/%s': %s",
- container, obj, error)
+ "Error downloading object '%s/%s': %s\n"
+ "Failed Transaction ID: %s",
+ container, obj, error,
+ getattr(error, 'transaction_id', 'unknown'))
except SwiftError as e:
- output_manager.error(e.value)
+ output_manager.error_with_txn_id(e)
except Exception as e:
output_manager.error(e)
@@ -670,7 +672,7 @@
prt_bytes(totals['bytes'], human))
except SwiftError as e:
- output_manager.error(e.value)
+ output_manager.error_with_txn_id(e)
st_stat_options = '''[--lh] [--header header:value]
@@ -754,21 +756,21 @@
items, headers, output_manager
)
else:
- raise(stat_result["error"])
+ raise stat_result["error"]
else:
output_manager.error(
'Usage: %s stat %s\n%s', BASENAME,
st_stat_options, st_stat_help)
except SwiftError as e:
- output_manager.error(e.value)
+ output_manager.error_with_txn_id(e)
st_post_options = '''[--read-acl <acl>] [--write-acl <acl>] [--sync-to <sync-to>]
[--sync-key <sync-key>] [--meta name:value]
[--header <header>]
[<container> [<object>]]
-'''
+''' # noqa
st_post_help = '''
Updates meta information for the account, container, or object.
@@ -864,10 +866,10 @@
else:
result = swift.post(container=container)
if not result["success"]:
- raise(result["error"])
+ raise result["error"]
except SwiftError as e:
- output_manager.error(e.value)
+ output_manager.error_with_txn_id(e)
st_copy_options = '''[--destination ] [--fresh-metadata]
@@ -972,7 +974,7 @@
return
except SwiftError as e:
- output_manager.error(e.value)
+ output_manager.error_with_txn_id(e)
st_upload_options = '''[--changed] [--skip-identical] [--segment-size <size>]
@@ -1270,7 +1272,7 @@
"to chunk the object")
except SwiftError as e:
- output_manager.error(e.value)
+ output_manager.error_with_txn_id(e)
st_capabilities_options = '''[--json] []
@@ -1332,7 +1334,7 @@
del capabilities['swift']
_print_compo_cap('Additional middleware', capabilities)
except SwiftError as e:
- output_manager.error(e.value)
+ output_manager.error_with_txn_id(e)
st_info = st_capabilities
@@ -1520,7 +1522,7 @@
Optional positional arguments:
<command> Swift client command to filter the flags by.
-'''.strip('\n')
+'''.strip('\n') # noqa
st_bash_completion_options = '''[command]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/test/unit/test_authv1.py new/python-swiftclient-4.6.0/test/unit/test_authv1.py
--- old/python-swiftclient-4.4.0/test/unit/test_authv1.py 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/test/unit/test_authv1.py 2024-05-23 10:01:23.000000000 +0200
@@ -16,10 +16,13 @@
import json
import unittest
from unittest import mock
-from keystoneauth1 import plugin
-from keystoneauth1 import loading
-from keystoneauth1 import exceptions
-from swiftclient import authv1
+try:
+ from keystoneauth1 import plugin
+ from keystoneauth1 import loading
+ from keystoneauth1 import exceptions
+ from swiftclient import authv1
+except ImportError:
+ plugin = loading = exceptions = authv1 = None
class TestDataNoAccount:
@@ -44,6 +47,10 @@
class TestPluginLoading(TestDataNoAccount, unittest.TestCase):
+ def setUp(self):
+ if authv1 is None:
+ raise unittest.SkipTest('keystoneauth1 is not available')
+
def test_can_load(self):
loader = loading.get_plugin_loader('v1password')
self.assertIsInstance(loader, authv1.PasswordLoader)
@@ -120,6 +127,8 @@
class TestPlugin(TestDataNoAccount, unittest.TestCase):
def setUp(self):
+ if authv1 is None:
+ raise unittest.SkipTest('keystoneauth1 is not available')
self.mock_session = mock.MagicMock()
self.mock_response = self.mock_session.get.return_value
self.mock_response.status_code = 200
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/test/unit/test_command_helpers.py new/python-swiftclient-4.6.0/test/unit/test_command_helpers.py
--- old/python-swiftclient-4.4.0/test/unit/test_command_helpers.py 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/test/unit/test_command_helpers.py 2024-05-23 10:01:23.000000000 +0200
@@ -18,6 +18,7 @@
from unittest import mock
from swiftclient import command_helpers as h
+from swiftclient.client import LowerKeyCaseInsensitiveDict
from swiftclient.multithreading import OutputManager
@@ -233,6 +234,33 @@
self.conn.head_object.return_value = stub_headers
args = ('c', 'o')
with self.output_manager as output_manager:
+ items, headers = h.stat_object(self.conn, self.options, *args)
+ h.print_object_stats(items, headers, output_manager)
+ expected = """
+ URL: http://storage/v1/a/c/o
+ Auth Token: tk12345
+ Account: a
+ Container: c
+ Object: o
+ Content Length: 1048576
+ ETag: 68b329da9893e34099c7d8ad5cb9c940
+ Meta Color: blue
+Content-Encoding: gzip
+"""
+ self.assertOut(expected)
+
+ def test_stat_object_case_insensitive_headers(self):
+ self.options['verbose'] += 1
+ # stub head object request
+ stub_headers = LowerKeyCaseInsensitiveDict({
+ 'content-length': 2 ** 20,
+ 'x-object-meta-color': 'blue',
+ 'ETag': '68b329da9893e34099c7d8ad5cb9c940',
+ 'content-encoding': 'gzip',
+ })
+ self.conn.head_object.return_value = stub_headers
+ args = ('c', 'o')
+ with self.output_manager as output_manager:
items, headers = h.stat_object(self.conn, self.options, *args)
h.print_object_stats(items, headers, output_manager)
expected = """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/test/unit/test_service.py new/python-swiftclient-4.6.0/test/unit/test_service.py
--- old/python-swiftclient-4.4.0/test/unit/test_service.py 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/test/unit/test_service.py 2024-05-23 10:01:23.000000000 +0200
@@ -31,7 +31,9 @@
import swiftclient
import swiftclient.utils as utils
-from swiftclient.client import Connection, ClientException
+from swiftclient.client import (
+ Connection, ClientException, LowerKeyCaseInsensitiveDict
+)
from swiftclient.service import (
SwiftService, SwiftError, SwiftUploadObject, SwiftDeleteObject
)
@@ -167,8 +169,10 @@
self.assertIsNone(sr._actual_md5)
# Check Contentlength raises error if it isn't an integer
- self.assertRaises(SwiftError, self.sr, 'path', 'body',
- {'content-length': 'notanint'})
+ with self.assertRaises(SwiftError) as cm:
+ self.sr('path', 'body', {'content-length': 'notanint'})
+ self.assertEqual("'content-length header must be an integer'",
+ str(cm.exception))
def test_iterator_usage(self):
def _consume(sr):
@@ -239,6 +243,26 @@
self.assertEqual(sr._actual_md5.hexdigest(),
md5('abc'.encode() * 3).hexdigest())
+ def test_swift_reader_knows_slo_etag_is_not_md5(self):
+ segment_bodies = [b'abc', b'def', b'ghi']
+ # slo etag is md5 of the sum of md5 of segments
+ slo_etag = md5(b''.join(
+ md5(b).hexdigest().encode()
+ for b in segment_bodies
+ )).hexdigest()
+ headers = LowerKeyCaseInsensitiveDict({
+ 'Content-Length': len(b''.join(segment_bodies)),
+ 'X-Static-Large-Object': 'true',
+ 'ETag': '"%s"' % slo_etag
+ })
+ sr = self.sr('path', segment_bodies, headers)
+ # x-static-large-object; so no exception is raised!
+ actual_md5 = md5(b''.join(sr)).hexdigest()
+ self.assertEqual(sr._actual_read, 9)
+ self.assertIsNone(sr._actual_md5)
+ self.assertEqual(actual_md5,
+ md5(b''.join(segment_bodies)).hexdigest())
+
class _TestServiceBase(unittest.TestCase):
def _get_mock_connection(self, attempts=2):
@@ -653,6 +677,7 @@
self.assertIsNone(se.exception)
self.assertEqual(str(se), '5')
+ self.assertNotIn(str(se), 'Transaction ID')
def test_swifterror_creation(self):
test_exc = Exception('test exc')
@@ -665,6 +690,25 @@
self.assertEqual(se.exception, test_exc)
self.assertEqual(str(se), '5 container:con object:obj segment:seg')
+ self.assertNotIn(str(se), 'Transaction ID')
+
+ def test_swifterror_clientexception_creation(self):
+ test_exc = ClientException(
+ Exception('test exc'),
+ http_response_headers=LowerKeyCaseInsensitiveDict({
+ 'x-trans-id': 'someTransId'})
+ )
+ se = SwiftError(5, 'con', 'obj', 'seg', test_exc)
+
+ self.assertEqual(se.value, 5)
+ self.assertEqual(se.container, 'con')
+ self.assertEqual(se.obj, 'obj')
+ self.assertEqual(se.segment, 'seg')
+ self.assertEqual(se.exception, test_exc)
+
+ self.assertEqual('someTransId', se.transaction_id)
+ self.assertNotIn('someTransId', str(se))
+ self.assertIn('5 container:con object:obj segment:seg', str(se))
class TestServiceUtils(unittest.TestCase):
@@ -1330,7 +1374,7 @@
options)
responses = [x for x in resp_iter]
for resp in responses:
- self.assertFalse('error' in resp)
+ self.assertNotIn('error', resp)
self.assertTrue(resp['success'])
self.assertEqual(5, len(responses))
container_resp, segment_container_resp = responses[0:2]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/test/unit/test_shell.py new/python-swiftclient-4.6.0/test/unit/test_shell.py
--- old/python-swiftclient-4.4.0/test/unit/test_shell.py 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/test/unit/test_shell.py 2024-05-23 10:01:23.000000000 +0200
@@ -15,6 +15,7 @@
import io
import contextlib
+import socket
from genericpath import getmtime
import getpass
import hashlib
@@ -26,8 +27,11 @@
from unittest import mock
import textwrap
from time import localtime, mktime, strftime, strptime
+from requests.exceptions import RequestException
+from urllib3.exceptions import HTTPError
import swiftclient
+from swiftclient.client import LowerKeyCaseInsensitiveDict
from swiftclient.service import SwiftError
import swiftclient.shell
import swiftclient.utils
@@ -160,6 +164,34 @@
' Bytes: 3\n')
@mock.patch('swiftclient.service.Connection')
+ def test_stat_account_with_quota(self, connection):
+ argv = ["", "stat", "--lh"]
+ return_headers = {
+ 'x-account-container-count': '2000',
+ 'x-account-object-count': '3000',
+ 'x-account-bytes-used': '4000000',
+ 'x-account-storage-policy-gold-bytes-used': '4000',
+ 'x-account-meta-quota-bytes': '5000000',
+ 'x-account-quota-bytes-policy-gold': '5000',
+ 'content-length': 0,
+ 'date': ''}
+ connection.return_value.head_account.return_value = return_headers
+ connection.return_value.url = 'http://127.0.0.1/v1/AUTH_account'
+ with CaptureOutput() as output:
+ swiftclient.shell.main(argv)
+
+ self.assertEqual(
+ output.out,
+ ' Account: AUTH_account\n'
+ ' Containers: 2000\n'
+ ' Objects: 2.9K\n'
+ ' Bytes: 3.8M\n'
+ ' Quota Bytes: 4.8M\n'
+ ' Objects in policy "gold": 0\n'
+ ' Bytes in policy "gold": 3.9K\n'
+ 'Quota Bytes for policy "gold": 4.9K\n')
+
+ @mock.patch('swiftclient.service.Connection')
def test_stat_account_with_headers(self, connection):
argv = ["", "stat", "-H", "Skip-Middleware: Test"]
return_headers = {
@@ -208,6 +240,28 @@
' Sync Key: secret\n')
@mock.patch('swiftclient.service.Connection')
+ def test_stat_container_not_found(self, connection):
+ connection.return_value.head_container.side_effect = \
+ swiftclient.ClientException(
+ 'test',
+ http_status=404,
+ http_response_headers=LowerKeyCaseInsensitiveDict({
+ 'x-trans-id': 'someTransId'})
+ )
+ argv = ["", "stat", "container"]
+
+ with CaptureOutput() as output:
+ with self.assertRaises(SystemExit):
+ swiftclient.shell.main(argv)
+ connection.return_value.head_container.assert_called_with(
+ 'container', headers={}, resp_chunk_size=65536,
+ response_dict={})
+
+ self.assertIn('Container \'container\' not found\n'
+ 'Failed Transaction ID: someTransId',
+ output.err)
+
+ @mock.patch('swiftclient.service.Connection')
def test_stat_container_with_headers(self, connection):
return_headers = {
'x-container-object-count': '1',
@@ -286,6 +340,27 @@
' Manifest: manifest\n')
@mock.patch('swiftclient.service.Connection')
+ def test_stat_object_not_found(self, connection):
+ connection.return_value.head_object.side_effect = \
+ swiftclient.ClientException(
+ 'test', http_status=404,
+ http_response_headers=LowerKeyCaseInsensitiveDict({
+ 'x-trans-id': 'someTransId'})
+ )
+ argv = ["", "stat", "container", "object"]
+
+ with CaptureOutput() as output:
+ with self.assertRaises(SystemExit):
+ swiftclient.shell.main(argv)
+ connection.return_value.head_object.assert_called_with(
+ 'container', 'object', headers={}, resp_chunk_size=65536,
+ response_dict={})
+
+ self.assertIn('test: 404\n'
+ 'Failed Transaction ID: someTransId',
+ output.err)
+
+ @mock.patch('swiftclient.service.Connection')
def test_stat_object_with_headers(self, connection):
return_headers = {
'x-object-manifest': 'manifest',
@@ -707,11 +782,122 @@
swiftclient.shell.main(argv)
self.assertEqual('objcontent', output.out)
+ def _do_test_download_clientexception(self, exc):
+ retry_calls = []
+
+ def _fake_retry(conn, *args, **kwargs):
+ retry_calls.append((args, kwargs))
+ conn.attempts += 1
+
+ body = mock.MagicMock()
+ body.resp.read.side_effect = RequestException('test_exc')
+ return (LowerKeyCaseInsensitiveDict({
+ 'content-type': 'text/plain',
+ 'etag': '2cbbfe139a744d6abbe695e17f3c1991',
+ 'x-trans-id': 'someTransId'}),
+ body)
+
+ argv = ["", "download", "container", "object", "--retries", "1"]
+ with CaptureOutput() as output:
+ with mock.patch(BUILTIN_OPEN) as mock_open:
+ with mock.patch("swiftclient.service.Connection._retry",
+ _fake_retry):
+ with self.assertRaises(SystemExit):
+ swiftclient.shell.main(argv)
+ mock_open.assert_called_with('object', 'wb', 65536)
+ self.assertEqual([
+ ((None, swiftclient.client.get_object, 'container', 'object'),
+ {'headers': {},
+ 'query_string': None,
+ 'resp_chunk_size': 65536,
+ 'response_dict': {}}),
+ ((None, swiftclient.client.get_object, 'container', 'object'),
+ {'attempts': 1,
+ 'headers': {'If-Match': mock.ANY, 'Range': 'bytes=0-'},
+ 'query_string': None,
+ 'resp_chunk_size': 65536,
+ 'response_dict': {}})],
+ retry_calls)
+ self.assertIn('Error downloading object \'container/object\': '
+ 'test_exc',
+ str(output.err))
+ self.assertIn('someTransId', str(output.err))
+
+ def test_download_request_exception(self):
+ self._do_test_download_clientexception(RequestException('text_exc'))
+
+ def test_download_socket_error(self):
+ self._do_test_download_clientexception(socket.error())
+
+ def test_download_http_error(self):
+ self._do_test_download_clientexception(HTTPError)
+
+ def test_download_request_exception_retries_0(self):
+ retry_calls = []
+
+ def _fake_retry(conn, *args, **kwargs):
+ retry_calls.append((args, kwargs))
+ conn.attempts += 1
+
+ body = mock.MagicMock()
+ body.__iter__.side_effect = RequestException('test_exc')
+ return (LowerKeyCaseInsensitiveDict({
+ 'content-type': 'text/plain',
+ 'etag': '2cbbfe139a744d6abbe695e17f3c1991',
+ 'x-trans-id': 'someTransId'}),
+ body)
+
+ argv = ["", "download", "container", "object", "--retries", "0"]
+ with CaptureOutput() as output:
+ with mock.patch(BUILTIN_OPEN) as mock_open:
+ with mock.patch("swiftclient.service.Connection._retry",
+ _fake_retry):
+ with self.assertRaises(SystemExit):
+ swiftclient.shell.main(argv)
+ mock_open.assert_called_with('object', 'wb', 65536)
+ self.assertEqual([
+ ((None, swiftclient.client.get_object, 'container', 'object'),
+ {'headers': {},
+ 'query_string': None,
+ 'resp_chunk_size': 65536,
+ 'response_dict': {}}), ],
+ retry_calls)
+ self.assertIn('Error downloading object \'container/object\': '
+ 'test_exc',
+ str(output.err))
+ self.assertIn('someTransId', str(output.err))
+
+ @mock.patch('swiftclient.service.Connection')
+ def test_download_bad_content_length(self, connection):
+ objcontent = io.BytesIO(b'objcontent')
+ connection.return_value.get_object.side_effect = [
+ (LowerKeyCaseInsensitiveDict({
+ 'content-type': 'text/plain',
+ 'content-length': 'BAD',
+ 'etag': '2cbbfe139a744d6abbe695e17f3c1991',
+ 'x-trans-id': 'someTransId'}),
+ objcontent)
+ ]
+ with CaptureOutput() as output:
+ with self.assertRaises(SystemExit):
+ with mock.patch(BUILTIN_OPEN) as mock_open:
+ argv = ["", "download", "container", "object"]
+ swiftclient.shell.main(argv)
+ connection.return_value.get_object.assert_called_with(
+ 'container', 'object', headers={}, resp_chunk_size=65536,
+ response_dict={})
+ mock_open.assert_called_with('object', 'wb', 65536)
+
+ self.assertIn("Error downloading object \'container/object\': "
+ "'content-length header must be an integer'"
+ "\nFailed Transaction ID: someTransId",
+ str(output.err))
+
@mock.patch('swiftclient.service.shuffle')
@mock.patch('swiftclient.service.Connection')
def test_download_shuffle(self, connection, mock_shuffle):
# Test that the container and object lists are shuffled
- mock_shuffle.side_effect = lambda l: l
+ mock_shuffle.side_effect = lambda to_shuffle: to_shuffle
connection.return_value.get_object.return_value = [
{'content-type': 'text/plain',
'etag': EMPTY_ETAG},
@@ -867,12 +1053,13 @@
fh.write(b'12345678901234567890')
swiftclient.shell.main(argv)
expected_calls = [mock.call('container',
- {'X-Storage-Policy': mock.ANY},
+ {'X-Storage-Policy': 'one'},
response_dict={}),
mock.call('container_segments',
- {'X-Storage-Policy': mock.ANY},
+ {'X-Storage-Policy': 'one'},
response_dict={})]
- connection.return_value.put_container.has_calls(expected_calls)
+ connection.return_value.put_container.assert_has_calls(expected_calls,
+ any_order=True)
connection.return_value.put_object.assert_called_with(
'container',
self.tmpfile.lstrip('/'),
@@ -1901,7 +2088,9 @@
with self.assertRaises(SystemExit):
swiftclient.shell.main(argv)
- self.assertEqual(output.err, 'Account not found\n')
+ self.assertEqual(
+ output.err,
+ 'Account not found\nFailed Transaction ID: unknown\n')
@mock.patch('swiftclient.service.Connection')
def test_post_container(self, connection):
@@ -2093,7 +2282,8 @@
self.assertEqual(
output.err,
'Combination of multiple objects and destination '
- 'including object is invalid\n')
+ 'including object is invalid\n'
+ 'Failed Transaction ID: unknown\n')
@mock.patch('swiftclient.service.Connection')
def test_copy_object_bad_auth(self, connection):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/test/unit/test_swiftclient.py new/python-swiftclient-4.6.0/test/unit/test_swiftclient.py
--- old/python-swiftclient-4.4.0/test/unit/test_swiftclient.py 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/test/unit/test_swiftclient.py 2024-05-23 10:01:23.000000000 +0200
@@ -579,7 +579,10 @@
self.assertTrue(token)
def test_auth_v3applicationcredential(self):
- from keystoneauth1 import exceptions as ksauthexceptions
+ try:
+ from keystoneauth1 import exceptions as ksauthexceptions
+ except ImportError:
+ raise unittest.SkipTest('keystoneauth1 is not available')
os_options = {
"auth_type": "v3applicationcredential",
@@ -1114,6 +1117,25 @@
self.assertEqual('t\xe9st', headers.get('x-utf-8-header', ''))
self.assertEqual('%ff', headers.get('x-non-utf-8-header', ''))
self.assertEqual('%FF', headers.get('x-binary-header', ''))
+ for k, v in headers.items():
+ # N.B. k is always lower case!
+ self.assertTrue(k.islower())
+ for k in headers.keys():
+ # N.B. k is always lower case!
+ self.assertTrue(k.islower())
+ self.assertTrue(set([
+ 'x-utf-8-header',
+ 'x-non-utf-8-header',
+ 'x-binary-header',
+ ]).intersection(headers))
+
+ self.assertEqual('t\xe9st', headers.get('X-Utf-8-Header', ''))
+ self.assertEqual('%ff', headers.get('X-Non-Utf-8-Header', ''))
+ self.assertEqual('%FF', headers.get('X-Binary-Header', ''))
+
+ self.assertEqual('t\xe9st', headers.get('X-UTF-8-HEADER', ''))
+ self.assertEqual('%ff', headers.get('X-NON-UTF-8-HEADER', ''))
+ self.assertEqual('%FF', headers.get('X-BINARY-HEADER', ''))
def test_chunk_size_read_method(self):
conn = c.Connection('http://auth.url/', 'some_user', 'some_key')
@@ -1997,7 +2019,7 @@
'authurl': 'http://www.test.com',
'tenant_name': 'atenant'}
conn = c.Connection(**args)
- self.assertEqual(type(conn), c.Connection)
+ self.assertIsInstance(conn, c.Connection)
def test_instance_kwargs_token(self):
args = {'preauthtoken': 'atoken123',
@@ -3053,7 +3075,7 @@
conn = c.Connection(url, 'asdf', 'asdf')
self.assertIsNone(conn.http_conn)
conn.http_conn = c.http_connection(url)
- self.assertEqual(type(conn.http_conn), tuple)
+ self.assertIsInstance(conn.http_conn, tuple)
self.assertEqual(len(conn.http_conn), 2)
http_conn_obj = conn.http_conn[1]
self.assertIsInstance(http_conn_obj, c.HTTPConnection)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/test-requirements.txt new/python-swiftclient-4.6.0/test-requirements.txt
--- old/python-swiftclient-4.4.0/test-requirements.txt 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/test-requirements.txt 2024-05-23 10:01:23.000000000 +0200
@@ -1,6 +1,7 @@
-hacking>=3.2.0,<3.3.0 # Apache-2.0
+hacking>=3.2.0,<6.2.0 # Apache-2.0
coverage!=4.4,>=4.0 # Apache-2.0
+python-keystoneclient>=0.7.0
keystoneauth1>=3.4.0 # Apache-2.0
stestr>=2.0.0,!=3.0.0 # Apache-2.0
openstacksdk>=0.11.0 # Apache-2.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-4.4.0/tox.ini new/python-swiftclient-4.6.0/tox.ini
--- old/python-swiftclient-4.4.0/tox.ini 2023-09-01 15:38:49.000000000 +0200
+++ new/python-swiftclient-4.6.0/tox.ini 2024-05-23 10:01:23.000000000 +0200
@@ -1,18 +1,18 @@
[tox]
envlist = py3,pep8
minversion = 3.18.0
-skipsdist = True
[testenv]
+skipsdist = True
usedevelop = True
list_dependencies_command = python -m pip freeze
setenv =
LANG=en_US.utf-8
VIRTUAL_ENV={envdir}
-deps = -r{toxinidir}/requirements.txt
+deps = -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
+ -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
- .[keystone]
commands = sh -c '(find . -not \( -type d -name .?\* -prune \) \
\( -type d -name "__pycache__" -or -type f -name "*.py[co]" \) \
-print0) | xargs -0 rm -rf'
@@ -24,6 +24,12 @@
commands =
python -m flake8 swiftclient test
+[testenv:{py36,py37}]
+# Drop the use of constraints; most dependencies have dropped support for
+# these versions already, and have updated their metadata to reflect that
+deps = -r{toxinidir}/requirements.txt
+ -r{toxinidir}/test-requirements.txt
+
[testenv:venv]
commands = {posargs}
@@ -69,7 +75,8 @@
# H404: multi line docstring should start without a leading new line
# H405: multi line docstring summary not separated with an empty line
# W504: line break after binary operator
-ignore = H101,H301,H306,H401,H403,H404,H405,W504
+# F811: Redefinition of unused name from line n
+ignore = H101,H301,H306,H401,H403,H404,H405,W504,F811
# H106: Don’t put vim configuration in source files
# H203: Use assertIs(Not)None to check for None
enable-extensions=H106,H203
@@ -87,8 +94,7 @@
[testenv:releasenotes]
usedevelop = False
-deps = -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
- -r{toxinidir}/doc/requirements.txt
+deps = {[testenv:docs]deps}
commands = sphinx-build -a -W -E -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
[testenv:pdf-docs]