Hello community, here is the log from the commit of package python-swiftclient for openSUSE:Factory checked in at 2019-12-04 13:49:02 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-swiftclient (Old) and /work/SRC/openSUSE:Factory/.python-swiftclient.new.4691 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-swiftclient" Wed Dec 4 13:49:02 2019 rev:27 rq:736670 version:3.8.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-swiftclient/python-swiftclient.changes 2019-05-03 22:43:21.907360024 +0200 +++ /work/SRC/openSUSE:Factory/.python-swiftclient.new.4691/python-swiftclient.changes 2019-12-04 14:19:01.262369397 +0100 @@ -1,0 +2,27 @@ +Wed Oct 9 13:07:20 UTC 2019 - cloud-de...@suse.de + +- update to version 3.8.1 + - Fix SLO re-upload + - Add Python 3 Train unit tests + - Clean up warnings from newer flake8 + - Optionally display listings in raw json + - docs: Fix warning treated as error + - Enable some off-by-default checks + - Add missing <sync-to> value in command line docs + - Delete/overwrite symlinks better + - Drag forward prettytable in lower-constraints + - Authors/changelog for 3.8.0 + - docs: Clean up formatting + - OpenDev Migration Patch + - Remove oslosphinx usage + - Authors/changelog for 3.8.1 + - Make proper functions instead of assigning lambdas + - Support pdb in tests better + - Replace git.openstack.org URLs with opendev.org URLs + - Update master for stable/stein + - Fix up requests so we can send non-RFC-compliant headers on py3 + - PDF Documentation Build tox target + - Isolate docs requirements + - Bump the openstackdocstheme extension to 1.20 + +------------------------------------------------------------------- Old: ---- python-swiftclient-3.7.0.tar.gz New: ---- python-swiftclient-3.8.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-swiftclient.spec ++++++ --- /var/tmp/diff_new_pack.RPe1v3/_old 2019-12-04 14:19:01.714369778 +0100 +++ /var/tmp/diff_new_pack.RPe1v3/_new 2019-12-04 14:19:01.718369781 +0100 @@ -17,14 +17,15 @@ Name: python-swiftclient -Version: 3.7.0 +Version: 3.8.1 Release: 0 Summary: OpenStack Object Storage API Client Library License: Apache-2.0 Group: Development/Languages/Python URL: https://launchpad.net/python-swiftclient -Source0: https://files.pythonhosted.org/packages/source/p/python-swiftclient/python-swiftclient-3.7.0.tar.gz +Source0: https://files.pythonhosted.org/packages/source/p/python-swiftclient/python-swiftclient-3.8.1.tar.gz BuildRequires: openstack-macros +BuildRequires: python2-futures >= 3.0.0 BuildRequires: python2-keystoneclient BuildRequires: python2-mock BuildRequires: python2-pbr @@ -60,10 +61,8 @@ %package -n python-swiftclient-doc Summary: %{summary} - Documentation Group: Documentation/HTML -BuildRequires: python-Sphinx -BuildRequires: python-futures >= 3.0.0 -BuildRequires: python-openstackdocstheme -Requires: %{name} = %{version} +BuildRequires: python3-Sphinx +BuildRequires: python3-openstackdocstheme %description -n python-swiftclient-doc This is a python client for the Swift API. There's a Python API (the @@ -72,12 +71,12 @@ This package contains documentation files for %{name}. %prep -%autosetup -p1 -n python-swiftclient-3.7.0 +%autosetup -p1 -n python-swiftclient-3.8.1 %py_req_cleanup %build %{python_build} -%{__python2} setup.py build_sphinx +PBR_VERSION=%{version} %sphinx_build -b html doc/source doc/build/html rm -rf doc/build/html/.{doctrees,buildinfo} %install ++++++ _service ++++++ --- /var/tmp/diff_new_pack.RPe1v3/_old 2019-12-04 14:19:01.742369801 +0100 +++ /var/tmp/diff_new_pack.RPe1v3/_new 2019-12-04 14:19:01.742369801 +0100 @@ -1,8 +1,8 @@ <services> <service mode="disabled" name="renderspec"> - <param name="input-template">https://raw.githubusercontent.com/openstack/rpm-packaging/stable/stein/openstack/python-swiftclient/python-swiftclient.spec.j2</param> + <param name="input-template">https://raw.githubusercontent.com/openstack/rpm-packaging/stable/train/openstack/python-swiftclient/python-swiftclient.spec.j2</param> <param name="output-name">python-swiftclient.spec</param> - <param name="requirements">https://raw.githubusercontent.com/openstack/python-swiftclient/stable/stein/requirements.txt</param> + <param name="requirements">https://raw.githubusercontent.com/openstack/python-swiftclient/stable/train/requirements.txt</param> <param name="changelog-email">cloud-de...@suse.de</param> <param name="changelog-provider">gh,openstack,python-swiftclient</param> </service> ++++++ python-swiftclient-3.7.0.tar.gz -> python-swiftclient-3.8.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/.zuul.yaml new/python-swiftclient-3.8.1/.zuul.yaml --- old/python-swiftclient-3.7.0/.zuul.yaml 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/.zuul.yaml 2019-09-13 23:39:55.000000000 +0200 @@ -9,7 +9,7 @@ # job sets zuul_work_dir to the swift directory and uses tox # for installation. required-projects: - - git.openstack.org/openstack/python-swiftclient + - opendev.org/openstack/python-swiftclient - job: name: swiftclient-functional @@ -19,10 +19,10 @@ python-swiftclient installed from source instead as package from PyPI. required-projects: - - git.openstack.org/openstack/python-swiftclient + - opendev.org/openstack/python-swiftclient vars: # Override value from parent job to use swiftclient tests - zuul_work_dir: "{{ zuul.projects['git.openstack.org/openstack/python-swiftclient'].src_dir }}" + zuul_work_dir: "{{ zuul.projects['opendev.org/openstack/python-swiftclient'].src_dir }}" - job: name: swiftclient-functional-py2 @@ -39,9 +39,7 @@ - openstack-lower-constraints-jobs - openstack-pypy-jobs-nonvoting - openstack-python-jobs - - openstack-python35-jobs - - openstack-python36-jobs - - openstack-python37-jobs + - openstack-python3-train-jobs - publish-openstack-docs-pti - release-notes-jobs-python3 check: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/AUTHORS new/python-swiftclient-3.8.1/AUTHORS --- old/python-swiftclient-3.7.0/AUTHORS 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/AUTHORS 2019-09-13 23:39:58.000000000 +0200 @@ -24,6 +24,7 @@ Claudiu Belu (cb...@cloudbasesolutions.com) Clay Gerrard (clay.gerr...@gmail.com) Clint Byrum (cl...@fewbar.com) +Corey Bryant (corey.bry...@canonical.com) Dan Prince (dpri...@redhat.com) Daniel Wakefield (daniel.wakefi...@hp.com) Darrell Bishop (darr...@swiftstack.com) @@ -52,6 +53,7 @@ howardlee (lihongwe...@inspur.com) Hu Bing (hubin...@cn.ibm.com) Ian Cordasco (ian.corda...@rackspace.com) +jacky06 (zhang....@99cloud.net) Jaivish Kothari (jaivish.koth...@nectechnologies.in) Jakub Krajcovic (jakub.krajco...@gmail.com) James Nzomo (james@tdt.rocks) @@ -99,6 +101,7 @@ Pallavi (pallav...@nectechnologies.in) Paul Belanger (pabelan...@redhat.com) Paulo Ewerton (pauloewer...@lsd.ufcg.edu.br) +pengyuesheng (pengyuesh...@gohighsec.com) Pete Zaitcev (zait...@kotori.zaitcev.us) Peter Lisak (peter.li...@firma.seznam.cz) Petr Kovar (pko...@redhat.com) @@ -147,6 +150,7 @@ Vu Cong Tuan (tua...@vn.fujitsu.com) wangqi (wang...@99cloud.net) wangxiyuan (wangxiy...@huawei.com) +wangzhenyu (wan...@fiberhome.com) Wu Wenxiang (wu.wenxi...@99cloud.net) wu.chunyang (wu.chuny...@99cloud.net) YangLei (yang...@cn.ibm.com) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/ChangeLog new/python-swiftclient-3.8.1/ChangeLog --- old/python-swiftclient-3.7.0/ChangeLog 2019-03-05 14:10:22.000000000 +0100 +++ new/python-swiftclient-3.8.1/ChangeLog 2019-09-13 23:39:58.000000000 +0200 @@ -1,3 +1,30 @@ +3.8.1 +----- + +* Deleting or overwriting a symlink to an SLO or DLO will no longer attempt + to clean up the large object's segments. + +* Fixed an issue sending non-ASCII metadata keys on Python 3. + Note that receiving such metadata on py3 is still broken; + see https://bugs.python.org/issue37093 + +* Documentation can now be rendered as a PDF. + +* Dropped Python 3.5 testing. + + +3.8.0 +----- + +* Added a new `--json` option to `swift list`. + +* Fixed an issue introduced in 3.5.0 where re-uploading an SLO with + the same size, mtime, and segment size would delete all of the + just-uploaded segments. + +* Various other minor bug fixes and improvements. + + 3.7.0 ----- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/PKG-INFO new/python-swiftclient-3.8.1/PKG-INFO --- old/python-swiftclient-3.7.0/PKG-INFO 2019-03-05 14:11:12.000000000 +0100 +++ new/python-swiftclient-3.8.1/PKG-INFO 2019-09-13 23:40:49.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: python-swiftclient -Version: 3.7.0 +Version: 3.8.1 Summary: OpenStack Object Storage API Client Library Home-page: https://docs.openstack.org/python-swiftclient/latest/ Author: OpenStack @@ -52,7 +52,7 @@ .. _Launchpad project: https://launchpad.net/python-swiftclient .. _Blueprints: https://blueprints.launchpad.net/python-swiftclient .. _Bugs: https://bugs.launchpad.net/python-swiftclient - .. _Source: https://git.openstack.org/cgit/openstack/python-swiftclient + .. _Source: https://opendev.org/openstack/python-swiftclient .. _How to Contribute: https://docs.openstack.org/infra/manual/developers.html .. _Specs: https://specs.openstack.org/openstack/swift-specs/ .. _Release Notes: https://docs.openstack.org/releasenotes/python-swiftclient @@ -72,7 +72,6 @@ Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Provides-Extra: test diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/README.rst new/python-swiftclient-3.8.1/README.rst --- old/python-swiftclient-3.7.0/README.rst 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/README.rst 2019-09-13 23:39:55.000000000 +0200 @@ -44,7 +44,7 @@ .. _Launchpad project: https://launchpad.net/python-swiftclient .. _Blueprints: https://blueprints.launchpad.net/python-swiftclient .. _Bugs: https://bugs.launchpad.net/python-swiftclient -.. _Source: https://git.openstack.org/cgit/openstack/python-swiftclient +.. _Source: https://opendev.org/openstack/python-swiftclient .. _How to Contribute: https://docs.openstack.org/infra/manual/developers.html .. _Specs: https://specs.openstack.org/openstack/swift-specs/ .. _Release Notes: https://docs.openstack.org/releasenotes/python-swiftclient diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/doc/requirements.txt new/python-swiftclient-3.8.1/doc/requirements.txt --- old/python-swiftclient-3.7.0/doc/requirements.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/python-swiftclient-3.8.1/doc/requirements.txt 2019-09-13 23:39:55.000000000 +0200 @@ -0,0 +1,5 @@ +keystoneauth1>=3.4.0 # Apache-2.0 +sphinx!=1.6.6,!=1.6.7,<2.0.0,>=1.6.2;python_version=='2.7' # BSD +sphinx!=1.6.6,!=1.6.7,!=2.1.0,>=1.6.2;python_version>='3.4' # BSD +reno>=2.5.0 # Apache-2.0 +openstackdocstheme>=1.20.0 # Apache-2.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/doc/source/cli/index.rst new/python-swiftclient-3.8.1/doc/source/cli/index.rst --- old/python-swiftclient-3.7.0/doc/source/cli/index.rst 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/doc/source/cli/index.rst 2019-09-13 23:39:55.000000000 +0200 @@ -245,13 +245,10 @@ --os-storage-url https://10.1.5.2:8080/v1/AUTH_ced809b6a4baea7aeab61a \ list -.. We need the backslash below in order to indent the note -\ +.. note:: - .. note:: - - Leftover environment variables are a common source of confusion when - authorization fails. + Leftover environment variables are a common source of confusion when + authorization fails. CLI commands ~~~~~~~~~~~~ @@ -446,7 +443,7 @@ .. code-block:: console - Usage: swift post [--read-acl <acl>] [--write-acl <acl>] [--sync-to] + Usage: swift post [--read-acl <acl>] [--write-acl <acl>] [--sync-to <sync-to>] [--sync-key <sync-key>] [--meta <name:value>] [--header <header>] [<container> [<object>]] @@ -739,15 +736,15 @@ But beyond that, ``time`` can also be specified as an ISO 8601 timestamp in one of following formats: - i) Complete date: YYYY-MM-DD (eg 1997-07-16) +i) Complete date: YYYY-MM-DD (e.g. 1997-07-16) - ii) Complete date plus hours, minutes and seconds: - YYYY-MM-DDThh:mm:ss - (eg 1997-07-16T19:20:30) - - iii) Complete date plus hours, minutes and seconds with UTC designator: - YYYY-MM-DDThh:mm:ssZ - (eg 1997-07-16T19:20:30Z) +ii) Complete date plus hours, minutes and seconds: + YYYY-MM-DDThh:mm:ss + (e.g. 1997-07-16T19:20:30) + +iii) Complete date plus hours, minutes and seconds with UTC designator: + YYYY-MM-DDThh:mm:ssZ + (e.g. 1997-07-16T19:20:30Z) Please be aware that if you don't provide the UTC designator (i.e., Z) the timestamp is generated using your local timezone. If only a date is @@ -881,17 +878,14 @@ testSwift.txt [auth 0.028s, headers 0.045s, total 0.045s, 0.002 MB/s] -.. We need the backslash below in order to indent the note -\ - - .. note:: +.. note:: - To upload an object to a container, your current working directory must be - where the file is located or you must provide the complete path to the file. - In other words, the --object-name <object-name> is an option that will upload - file and name object to <object-name> or upload directory and use <object-name> as - object prefix. In the case that you provide the complete path of the file, - that complete path will be the name of the uploaded object. + To upload an object to a container, your current working directory must be + where the file is located or you must provide the complete path to the file. + In other words, the --object-name <object-name> is an option that will upload + file and name object to <object-name> or upload directory and use <object-name> as + object prefix. In the case that you provide the complete path of the file, + that complete path will be the name of the uploaded object. For example: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/doc/source/conf.py new/python-swiftclient-3.8.1/doc/source/conf.py --- old/python-swiftclient-3.7.0/doc/source/conf.py 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/doc/source/conf.py 2019-09-13 23:39:55.000000000 +0200 @@ -53,17 +53,8 @@ master_doc = 'index' # General information about the project. -project = u'Swiftclient' copyright = u'2013-2016 OpenStack, LLC.' -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -import swiftclient.version -release = swiftclient.version.version_string -version = swiftclient.version.version_string - # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # language = None @@ -190,7 +181,7 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]) latex_documents = [ - ('index', 'SwiftClient.tex', u'SwiftClient Documentation', + ('index', 'doc-python-swiftclient.tex', u'SwiftClient Documentation', u'OpenStack, LLC.', 'manual'), ] @@ -210,3 +201,5 @@ # If false, no module index is generated. # latex_use_modindex = True + +latex_use_xindy = False diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/doc/source/index.rst new/python-swiftclient-3.8.1/doc/source/index.rst --- old/python-swiftclient-3.7.0/doc/source/index.rst 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/doc/source/index.rst 2019-09-13 23:39:55.000000000 +0200 @@ -39,17 +39,17 @@ License ~~~~~~~ - Copyright 2013 OpenStack, LLC. +Copyright 2013 OpenStack, LLC. - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +* http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/doc/source/introduction.rst new/python-swiftclient-3.8.1/doc/source/introduction.rst --- old/python-swiftclient-3.7.0/doc/source/introduction.rst 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/doc/source/introduction.rst 2019-09-13 23:39:55.000000000 +0200 @@ -16,41 +16,41 @@ Alongside the command line tool, the ``python-swiftclient`` includes two levels of API: - * A low level client API that provides simple Python wrappers around the - various authentication mechanisms and the individual HTTP requests. - * A high level service API that provides methods for performing common - operations in parallel on a thread pool. +* A low level client API that provides simple Python wrappers around the + various authentication mechanisms and the individual HTTP requests. +* A high level service API that provides methods for performing common + operations in parallel on a thread pool. Example use cases: - * Uploading and retrieving data - Use the command line tool if you are simply uploading and downloading - files and directories to and from your filesystem. The command line tool - can be integrated into a shell script to automate tasks. - - * Integrating into an automated Python workflow - Use the ``SwiftService`` API to perform operations offered by the CLI - if your use case requires integration with a Python-based workflow. - This method offers greater control and flexibility over individual object - operations, such as the metadata set on each object. The ``SwiftService`` - class provides methods to perform multiple sets of operations against a - swift object store using a configurable shared thread pool. A single - instance of the ``SwiftService`` class can be shared between multiple - threads in your own code. - - * Developing an application in Python to access a swift object store - Use the ``SwiftService`` API to develop Python applications that use - swift to store and retrieve objects. A ``SwiftService`` instance provides - a configurable thread pool for performing all operations supported by the - CLI. - - * Fine-grained control over threading or the requests being performed - Use the ``Connection`` API if your use case requires fine grained control - over advanced features or you wish to use your own existing threading - model. Examples of advanced features requiring the use of the - ``Connection`` API include creating an SLO manifest that references - already existing objects, or fine grained control over the query strings - supplied with each HTTP request. +* Uploading and retrieving data + Use the command line tool if you are simply uploading and downloading + files and directories to and from your filesystem. The command line tool + can be integrated into a shell script to automate tasks. + +* Integrating into an automated Python workflow + Use the ``SwiftService`` API to perform operations offered by the CLI + if your use case requires integration with a Python-based workflow. + This method offers greater control and flexibility over individual object + operations, such as the metadata set on each object. The ``SwiftService`` + class provides methods to perform multiple sets of operations against a + swift object store using a configurable shared thread pool. A single + instance of the ``SwiftService`` class can be shared between multiple + threads in your own code. + +* Developing an application in Python to access a swift object store + Use the ``SwiftService`` API to develop Python applications that use + swift to store and retrieve objects. A ``SwiftService`` instance provides + a configurable thread pool for performing all operations supported by the + CLI. + +* Fine-grained control over threading or the requests being performed + Use the ``Connection`` API if your use case requires fine grained control + over advanced features or you wish to use your own existing threading + model. Examples of advanced features requiring the use of the + ``Connection`` API include creating an SLO manifest that references + already existing objects, or fine grained control over the query strings + supplied with each HTTP request. Important considerations ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -66,19 +66,19 @@ There are two main restrictions to bear in mind when designing an application that uses an object store: - * You cannot rename objects. Due to fact that the name of an object is one - of the factors that determines where the object and its replicas are stored, - renaming would require multiple copies of the data to be moved between - physical storage devices. If you want to rename an object you must upload - to the new location, or make a server side copy request to the new location, - and then delete the original. - - * You cannot modify objects. Objects are stored in multiple locations and - are checked for integrity based on the MD5 sum calculated during - upload. In order to modify the contents of an object, the entire desired - contents must be re-uploaded. In certain special cases it is possible to - work around this restriction using large objects, but no general - file-like access is available to modify a stored object. +* You cannot rename objects. Due to fact that the name of an object is one + of the factors that determines where the object and its replicas are stored, + renaming would require multiple copies of the data to be moved between + physical storage devices. If you want to rename an object you must upload + to the new location, or make a server side copy request to the new location, + and then delete the original. + +* You cannot modify objects. Objects are stored in multiple locations and + are checked for integrity based on the MD5 sum calculated during + upload. In order to modify the contents of an object, the entire desired + contents must be re-uploaded. In certain special cases it is possible to + work around this restriction using large objects, but no general + file-like access is available to modify a stored object. Objects cannot be locked ------------------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/doc/source/service-api.rst new/python-swiftclient-3.8.1/doc/source/service-api.rst --- old/python-swiftclient-3.7.0/doc/source/service-api.rst 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/doc/source/service-api.rst 2019-09-13 23:39:55.000000000 +0200 @@ -26,10 +26,10 @@ supplying options from multiple different auth versions can cause unexpected behaviour. - .. note:: +.. note:: - Leftover environment variables are a common source of confusion when - authorization fails. + Leftover environment variables are a common source of confusion when + authorization fails. Keystone V3 ~~~~~~~~~~~ @@ -109,17 +109,17 @@ Options ~~~~~~~ - ``retries``: ``5`` +``retries``: ``5`` The number of times that the library should attempt to retry HTTP actions before giving up and reporting a failure. - ``container_threads``: ``10`` +``container_threads``: ``10`` - ``object_dd_threads``: ``10`` +``object_dd_threads``: ``10`` - ``object_uu_threads``: ``10`` +``object_uu_threads``: ``10`` - ``segment_threads``: ``10`` +``segment_threads``: ``10`` The above options determine the size of the available thread pools for performing swift operations. Container operations (such as listing a container) operate in the container threads, and a similar pattern @@ -131,86 +131,86 @@ ``uu`` and ``dd``. This stands for "upload/update" and "download/delete", and the corresponding actions will be run on separate threads pools. - ``segment_size``: ``None`` +``segment_size``: ``None`` If specified, this option enables uploading of large objects. Should the object being uploaded be larger than 5G in size, this option is mandatory otherwise the upload will fail. This option should be specified as a size in bytes. - ``use_slo``: ``False`` +``use_slo``: ``False`` Used in combination with the above option, ``use_slo`` will upload large objects as static rather than dynamic. Only static large objects provide error checking for the downloaded object, so we recommend this option. - ``segment_container``: ``None`` +``segment_container``: ``None`` Allows the user to select the container into which large object segments will be uploaded. We do not recommend changing this value as it could make locating orphaned segments more difficult in the case of errors. - ``leave_segments``: ``False`` +``leave_segments``: ``False`` Setting this option to true means that when deleting or overwriting a large object, its segments will be left in the object store and must be cleaned up manually. This option can be useful when sharing large object segments between multiple objects in more advanced scenarios, but must be treated with care, as it could lead to ever increasing storage usage. - ``changed``: ``None`` +``changed``: ``None`` This option affects uploads and simply means that those objects which already exist in the object store will not be overwritten if the ``mtime`` and size of the source is the same as the existing object. - ``skip_identical``: ``False`` +``skip_identical``: ``False`` A slightly more thorough case of the above, but rather than ``mtime`` and size uses an object's ``MD5 sum``. - ``yes_all``: ``False`` +``yes_all``: ``False`` This options affects only download and delete, and in each case must be specified in order to download/delete the entire contents of an account. This option has no effect on any other calls. - ``no_download``: ``False`` +``no_download``: ``False`` This option only affects download and means that all operations proceed as normal with the exception that no data is written to disk. - ``header``: ``[]`` +``header``: ``[]`` Used with upload and post operations to set headers on objects. Headers are specified as colon separated strings, e.g. "content-type:text/plain". - ``meta``: ``[]`` +``meta``: ``[]`` Used to set metadata on an object similarly to headers. .. note:: Setting metadata is a destructive operation, so when updating one of many metadata values all desired metadata for an object must be re-applied. - ``long``: ``False`` +``long``: ``False`` Affects only list operations, and results in more metrics being made available in the results at the expense of lower performance. - ``fail_fast``: ``False`` +``fail_fast``: ``False`` Applies to delete and upload operations, and attempts to abort queued tasks in the event of errors. - ``prefix``: ``None`` +``prefix``: ``None`` Affects list operations; only objects with the given prefix will be returned/affected. It is not advisable to set at the service level, as those operations that call list to discover objects on which they should operate will also be affected. - ``delimiter``: ``None`` +``delimiter``: ``None`` Affects list operations, and means that listings only contain results up to the first instance of the delimiter in the object name. This is useful for working with objects containing '/' in their names to simulate folder structures. - ``dir_marker``: ``False`` +``dir_marker``: ``False`` Affects uploads, and allows empty 'pseudofolder' objects to be created when the source of an upload is ``None``. - ``checksum``: ``True`` +``checksum``: ``True`` Affects uploads and downloads. If set check md5 sum for the transfer. - ``shuffle``: ``False`` +``shuffle``: ``False`` When downloading objects, the default behaviour of the CLI is to shuffle lists of objects in order to spread the load on storage drives when multiple clients are downloading the same files to multiple locations (e.g. in the @@ -220,12 +220,12 @@ are downloaded in lexically-sorted order. Setting this option to ``True`` gives the same shuffling behaviour as the CLI. - ``destination``: ``None`` +``destination``: ``None`` When copying objects, this specifies the destination where the object will be copied to. The default of None means copy will be the same as source. - ``fresh_metadata``: ``None`` +``fresh_metadata``: ``None`` When copying objects, this specifies that the object metadata on the source will *not* be applied to the destination object - the destination object will have a new fresh set of metadata that includes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/lower-constraints.txt new/python-swiftclient-3.8.1/lower-constraints.txt --- old/python-swiftclient-3.7.0/lower-constraints.txt 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/lower-constraints.txt 2019-09-13 23:39:55.000000000 +0200 @@ -20,12 +20,11 @@ mccabe==0.2.1 mock==1.2.0 netaddr==0.7.10 -openstackdocstheme==1.18.1 +openstackdocstheme==1.20.0 oslo.config==1.2.0 -oslosphinx==4.7.0 pbr==2.0.0 pep8==1.5.7 -PrettyTable==0.7 +PrettyTable==0.7.1 pyflakes==0.8.1 Pygments==2.2.0 python-keystoneclient==0.7.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/python_swiftclient.egg-info/PKG-INFO new/python-swiftclient-3.8.1/python_swiftclient.egg-info/PKG-INFO --- old/python-swiftclient-3.7.0/python_swiftclient.egg-info/PKG-INFO 2019-03-05 14:11:12.000000000 +0100 +++ new/python-swiftclient-3.8.1/python_swiftclient.egg-info/PKG-INFO 2019-09-13 23:40:49.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: python-swiftclient -Version: 3.7.0 +Version: 3.8.1 Summary: OpenStack Object Storage API Client Library Home-page: https://docs.openstack.org/python-swiftclient/latest/ Author: OpenStack @@ -52,7 +52,7 @@ .. _Launchpad project: https://launchpad.net/python-swiftclient .. _Blueprints: https://blueprints.launchpad.net/python-swiftclient .. _Bugs: https://bugs.launchpad.net/python-swiftclient - .. _Source: https://git.openstack.org/cgit/openstack/python-swiftclient + .. _Source: https://opendev.org/openstack/python-swiftclient .. _How to Contribute: https://docs.openstack.org/infra/manual/developers.html .. _Specs: https://specs.openstack.org/openstack/swift-specs/ .. _Release Notes: https://docs.openstack.org/releasenotes/python-swiftclient @@ -72,7 +72,6 @@ Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Provides-Extra: test diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/python_swiftclient.egg-info/SOURCES.txt new/python-swiftclient-3.8.1/python_swiftclient.egg-info/SOURCES.txt --- old/python-swiftclient-3.7.0/python_swiftclient.egg-info/SOURCES.txt 2019-03-05 14:11:12.000000000 +0100 +++ new/python-swiftclient-3.8.1/python_swiftclient.egg-info/SOURCES.txt 2019-09-13 23:40:49.000000000 +0200 @@ -21,6 +21,7 @@ tox.ini bin/swift doc/Makefile +doc/requirements.txt doc/manpages/swift.1 doc/source/client-api.rst doc/source/conf.py @@ -28,6 +29,7 @@ doc/source/introduction.rst doc/source/service-api.rst doc/source/swiftclient.rst +doc/source/_static/.gitignore doc/source/_templates/.empty doc/source/cli/index.rst examples/capabilities.py @@ -52,6 +54,8 @@ releasenotes/notes/350_notes-ad0ae19704b2eb88.yaml releasenotes/notes/360_notes-1ec385df13a3a735.yaml releasenotes/notes/361_notes-59e020e68bcdd709.yaml +releasenotes/notes/3_8_0_release-bd867fbdb8c895d3.yaml +releasenotes/notes/3_8_1_release-cb5648c3ae69bde1.yaml releasenotes/source/conf.py releasenotes/source/current.rst releasenotes/source/index.rst @@ -60,6 +64,7 @@ releasenotes/source/pike.rst releasenotes/source/queens.rst releasenotes/source/rocky.rst +releasenotes/source/stein.rst swiftclient/__init__.py swiftclient/authv1.py swiftclient/client.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/python_swiftclient.egg-info/pbr.json new/python-swiftclient-3.8.1/python_swiftclient.egg-info/pbr.json --- old/python-swiftclient-3.7.0/python_swiftclient.egg-info/pbr.json 2019-03-05 14:11:12.000000000 +0100 +++ new/python-swiftclient-3.8.1/python_swiftclient.egg-info/pbr.json 2019-09-13 23:40:49.000000000 +0200 @@ -1 +1 @@ -{"git_version": "991a6ce", "is_release": true} \ No newline at end of file +{"git_version": "72b90fe", "is_release": true} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/python_swiftclient.egg-info/requires.txt new/python-swiftclient-3.8.1/python_swiftclient.egg-info/requires.txt --- old/python-swiftclient-3.7.0/python_swiftclient.egg-info/requires.txt 2019-03-05 14:11:12.000000000 +0100 +++ new/python-swiftclient-3.8.1/python_swiftclient.egg-info/requires.txt 2019-09-13 23:40:49.000000000 +0200 @@ -12,8 +12,4 @@ coverage!=4.4,>=4.0 keystoneauth1>=3.4.0 mock>=1.2.0 -oslosphinx>=4.7.0 -sphinx!=1.6.6,!=1.6.7,>=1.6.2 stestr>=2.0.0 -reno>=2.5.0 -openstackdocstheme>=1.18.1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/releasenotes/notes/3_8_0_release-bd867fbdb8c895d3.yaml new/python-swiftclient-3.8.1/releasenotes/notes/3_8_0_release-bd867fbdb8c895d3.yaml --- old/python-swiftclient-3.7.0/releasenotes/notes/3_8_0_release-bd867fbdb8c895d3.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/python-swiftclient-3.8.1/releasenotes/notes/3_8_0_release-bd867fbdb8c895d3.yaml 2019-09-13 23:39:55.000000000 +0200 @@ -0,0 +1,9 @@ +--- +features: + - | + Added a new ``--json`` option to ``swift list``. +fixes: + - | + Fixed an issue introduced in 3.5.0 where re-uploading an SLO with + the same size, mtime, and segment size would delete all of the + just-uploaded segments. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/releasenotes/notes/3_8_1_release-cb5648c3ae69bde1.yaml new/python-swiftclient-3.8.1/releasenotes/notes/3_8_1_release-cb5648c3ae69bde1.yaml --- old/python-swiftclient-3.7.0/releasenotes/notes/3_8_1_release-cb5648c3ae69bde1.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/python-swiftclient-3.8.1/releasenotes/notes/3_8_1_release-cb5648c3ae69bde1.yaml 2019-09-13 23:39:58.000000000 +0200 @@ -0,0 +1,14 @@ +--- +fixes: + - | + Deleting or overwriting a symlink to an SLO or DLO will no longer attempt + to clean up the large object's segments. + - | + Fixed an issue sending non-ASCII metadata keys on Python 3. + Note that *receiving* such metadata on py3 is `still broken + <https://bugs.python.org/issue37093>`__. +other: + - | + Documentation can now be rendered as a PDF. + - | + Dropped Python 3.5 testing. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/releasenotes/source/conf.py new/python-swiftclient-3.8.1/releasenotes/source/conf.py --- old/python-swiftclient-3.7.0/releasenotes/source/conf.py 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/releasenotes/source/conf.py 2019-09-13 23:39:55.000000000 +0200 @@ -65,15 +65,8 @@ master_doc = 'index' # General information about the project. -project = u'Swift Client Release Notes' copyright = u'%d, OpenStack Foundation' % datetime.datetime.now().year -# Release notes are version independent. -# The short X.Y version. -version = '' -# The full version, including alpha/beta/rc tags. -release = '' - # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # @@ -173,11 +166,6 @@ # # html_extra_path = [] -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -# html_last_updated_fmt = '%b %d, %Y' -html_last_updated_fmt = '%Y-%m-%d %H:%M' - # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. # diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/releasenotes/source/index.rst new/python-swiftclient-3.8.1/releasenotes/source/index.rst --- old/python-swiftclient-3.7.0/releasenotes/source/index.rst 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/releasenotes/source/index.rst 2019-09-13 23:39:55.000000000 +0200 @@ -6,6 +6,7 @@ :maxdepth: 1 current + stein rocky queens pike diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/releasenotes/source/stein.rst new/python-swiftclient-3.8.1/releasenotes/source/stein.rst --- old/python-swiftclient-3.7.0/releasenotes/source/stein.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/python-swiftclient-3.8.1/releasenotes/source/stein.rst 2019-09-13 23:39:55.000000000 +0200 @@ -0,0 +1,6 @@ +=================================== + Stein Series Release Notes +=================================== + +.. release-notes:: + :branch: stable/stein diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/setup.cfg new/python-swiftclient-3.8.1/setup.cfg --- old/python-swiftclient-3.7.0/setup.cfg 2019-03-05 14:11:12.000000000 +0100 +++ new/python-swiftclient-3.8.1/setup.cfg 2019-09-13 23:40:49.000000000 +0200 @@ -17,7 +17,6 @@ Programming Language :: Python :: 2 Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 - Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/swiftclient/client.py new/python-swiftclient-3.8.1/swiftclient/client.py --- old/python-swiftclient-3.7.0/swiftclient/client.py 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/swiftclient/client.py 2019-09-13 23:39:55.000000000 +0200 @@ -39,7 +39,7 @@ # Default is 100, increase to 256 http_client._MAXHEADERS = 256 -VERSIONFUL_AUTH_PATH = re.compile('v[2-3](?:\.0)?$') +VERSIONFUL_AUTH_PATH = re.compile(r'v[2-3](?:\.0)?$') AUTH_VERSIONS_V1 = ('1.0', '1', 1) AUTH_VERSIONS_V2 = ('2.0', '2', 2) AUTH_VERSIONS_V3 = ('3.0', '3', 3) @@ -74,8 +74,10 @@ pass # requests version 1.2.3 try to encode headers in ascii, preventing -# utf-8 encoded header to be 'prepared' -if StrictVersion(requests.__version__) < StrictVersion('2.0.0'): +# utf-8 encoded header to be 'prepared'. This also affects all +# (or at least most) versions of requests on py3 +if StrictVersion(requests.__version__) < StrictVersion('2.0.0') \ + or not six.PY2: from requests.structures import CaseInsensitiveDict def prepare_unicode_headers(self, headers): @@ -1885,7 +1887,9 @@ reset = getattr(contents, 'reset', None) if tell and seek: orig_pos = tell() - reset_func = lambda *a, **k: seek(orig_pos) + + def reset_func(*a, **kw): + seek(orig_pos) elif reset: reset_func = reset return self._retry(reset_func, put_object, container, obj, contents, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/swiftclient/multithreading.py new/python-swiftclient-3.8.1/swiftclient/multithreading.py --- old/python-swiftclient-3.7.0/swiftclient/multithreading.py 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/swiftclient/multithreading.py 2019-09-13 23:39:55.000000000 +0200 @@ -168,6 +168,12 @@ We will only create as many connections as are required concurrently. """ def __init__(self, create_connection, max_workers): + """ + Initializes a new ThreadPoolExecutor instance. + + :param create_connection: callable to use to create new connections + :param max_workers: the maximum number of threads that can be used + """ self._connections = PriorityQueue() self._create_connection = create_connection for p in range(0, max_workers): @@ -175,6 +181,14 @@ super(ConnectionThreadPoolExecutor, self).__init__(max_workers) def submit(self, fn, *args, **kwargs): + """ + Schedules the callable, `fn`, to be executed + + :param fn: the callable to be invoked + :param args: the positional arguments for the callable + :param kwargs: the keyword arguments for the callable + :returns: a Future object representing the execution of the callable + """ def conn_fn(): priority = None conn = None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/swiftclient/service.py new/python-swiftclient-3.8.1/swiftclient/service.py --- old/python-swiftclient-3.7.0/swiftclient/service.py 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/swiftclient/service.py 2019-09-13 23:39:55.000000000 +0200 @@ -17,6 +17,7 @@ import os +from collections import defaultdict from concurrent.futures import as_completed, CancelledError, TimeoutError from copy import deepcopy from errno import EEXIST, ENOENT @@ -44,7 +45,7 @@ from swiftclient.utils import ( config_true_value, ReadableToIterable, LengthWrapper, EMPTY_ETAG, parse_api_response, report_traceback, n_groups, split_request_headers, - n_at_a_time + n_at_a_time, normalize_manifest_path ) from swiftclient.exceptions import ClientException from swiftclient.multithreading import MultiThreadingManager @@ -173,6 +174,7 @@ 'container_threads': 10 } + _default_global_options = _build_default_global_options() _default_local_options = { @@ -451,7 +453,9 @@ **_default_local_options ) process_options(self._options) - create_connection = lambda: get_conn(self._options) + + def create_connection(): + return get_conn(self._options) self.thread_manager = MultiThreadingManager( create_connection, segment_threads=self._options['segment_threads'], @@ -2066,14 +2070,13 @@ 'status': 'skipped-changed' }) return res - if not options['leave_segments']: + if not options['leave_segments'] and not headers.get( + 'content-location'): old_manifest = headers.get('x-object-manifest') if is_slo: - for old_seg in chunk_data: - seg_path = old_seg['name'].lstrip('/') - if isinstance(seg_path, text_type): - seg_path = seg_path.encode('utf-8') - old_slo_manifest_paths.append(seg_path) + old_slo_manifest_paths.extend( + normalize_manifest_path(old_seg['name']) + for old_seg in chunk_data) except ClientException as err: if err.http_status != 404: traceback, err_time = report_traceback() @@ -2163,8 +2166,9 @@ response = self._upload_slo_manifest( conn, segment_results, container, obj, put_headers) res['manifest_response_dict'] = response - new_slo_manifest_paths = { - seg['segment_location'] for seg in segment_results} + new_slo_manifest_paths.update( + normalize_manifest_path(new_seg['segment_location']) + for new_seg in segment_results) else: new_object_manifest = '%s/%s/%s/%s/%s/' % ( quote(seg_container.encode('utf8')), @@ -2221,8 +2225,9 @@ response = self._upload_slo_manifest( conn, results, container, obj, put_headers) res['manifest_response_dict'] = response - new_slo_manifest_paths = { - r['segment_location'] for r in results} + new_slo_manifest_paths.update( + normalize_manifest_path(new_seg['segment_location']) + for new_seg in results) res['large_object'] = True else: res['response_dict'] = ret @@ -2262,11 +2267,10 @@ fp.close() if old_manifest or old_slo_manifest_paths: drs = [] - delobjsmap = {} + delobjsmap = defaultdict(list) if old_manifest: scontainer, sprefix = old_manifest.split('/', 1) sprefix = sprefix.rstrip('/') + '/' - delobjsmap[scontainer] = [] for part in self.list(scontainer, {'prefix': sprefix}): if not part["success"]: raise part["error"] @@ -2278,10 +2282,8 @@ if seg_to_delete in new_slo_manifest_paths: continue scont, sobj = \ - seg_to_delete.split(b'/', 1) - delobjs_cont = delobjsmap.get(scont, []) - delobjs_cont.append(sobj) - delobjsmap[scont] = delobjs_cont + seg_to_delete.split('/', 1) + delobjsmap[scont].append(sobj) del_segs = [] for dscont, dsobjs in delobjsmap.items(): @@ -2514,7 +2516,8 @@ if not options['leave_segments']: try: headers = conn.head_object(container, obj, - headers=_headers) + headers=_headers, + query_string='symlink=get') old_manifest = headers.get('x-object-manifest') if config_true_value(headers.get('x-static-large-object')): query_string = 'multipart-manifest=delete' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/swiftclient/shell.py new/python-swiftclient-3.8.1/swiftclient/shell.py --- old/python-swiftclient-3.7.0/swiftclient/shell.py 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/swiftclient/shell.py 2019-09-13 23:39:55.000000000 +0200 @@ -33,7 +33,8 @@ from time import gmtime, strftime from swiftclient import RequestException -from swiftclient.utils import config_true_value, generate_temp_url, prt_bytes +from swiftclient.utils import config_true_value, generate_temp_url, \ + prt_bytes, JSONableIterable from swiftclient.multithreading import OutputManager from swiftclient.exceptions import ClientException from swiftclient import __version__ as client_version @@ -58,6 +59,7 @@ stderr.write(" Aborted\n") os_exit(2) + st_delete_options = '''[--all] [--leave-segments] [--object-threads <threads>] [--container-threads <threads>] @@ -577,6 +579,8 @@ help='Roll up items with the given delimiter. For containers ' 'only. See OpenStack Swift API documentation for ' 'what this means.') + parser.add_argument('-j', '--json', action='store_true', + help='print listing information in json') parser.add_argument( '-H', '--header', action='append', dest='header', default=[], @@ -615,6 +619,20 @@ else: stats_parts_gen = swift.list(container=container) + if options.get('json', False): + def listing(stats_parts_gen=stats_parts_gen): + for stats in stats_parts_gen: + if stats["success"]: + for item in stats['listing']: + yield item + else: + raise stats["error"] + + json.dump( + JSONableIterable(listing()), output_manager.print_stream, + sort_keys=True, indent=2) + output_manager.print_msg('') + return for stats in stats_parts_gen: if stats["success"]: _print_stats(options, stats, human) @@ -708,7 +726,7 @@ output_manager.error(e.value) -st_post_options = '''[--read-acl <acl>] [--write-acl <acl>] [--sync-to] +st_post_options = '''[--read-acl <acl>] [--write-acl <acl>] [--sync-to <sync-to>] [--sync-key <sync-key>] [--meta <name:value>] [--header <header>] [<container> [<object>]] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/swiftclient/utils.py new/python-swiftclient-3.8.1/swiftclient/utils.py --- old/python-swiftclient-3.7.0/swiftclient/utils.py 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/swiftclient/utils.py 2019-09-13 23:39:55.000000000 +0200 @@ -74,7 +74,7 @@ Swift object. :param path: The full path to the Swift object or prefix if - a prefix-based temporary URL should be generated. Example: + a prefix-based temporary URL should be generated. Example: /v1/AUTH_account/c/o or /v1/AUTH_account/c/prefix. :param seconds: time in seconds or ISO 8601 timestamp. If absolute is False and this is the string representation of an @@ -395,3 +395,33 @@ def n_groups(seq, n): items_per_group = ((len(seq) - 1) // n) + 1 return n_at_a_time(seq, items_per_group) + + +def normalize_manifest_path(path): + if six.PY2 and isinstance(path, six.text_type): + path = path.encode('utf-8') + if path.startswith('/'): + return path[1:] + return path + + +class JSONableIterable(list): + def __init__(self, iterable): + self._iterable = iter(iterable) + try: + self._peeked = next(self._iterable) + self._has_items = True + except StopIteration: + self._peeked = None + self._has_items = False + + def __bool__(self): + return self._has_items + + __nonzero__ = __bool__ + + def __iter__(self): + if self._has_items: + yield self._peeked + for item in self._iterable: + yield item diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/test-requirements.txt new/python-swiftclient-3.8.1/test-requirements.txt --- old/python-swiftclient-3.7.0/test-requirements.txt 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/test-requirements.txt 2019-09-13 23:39:55.000000000 +0200 @@ -3,8 +3,4 @@ coverage!=4.4,>=4.0 # Apache-2.0 keystoneauth1>=3.4.0 # Apache-2.0 mock>=1.2.0 # BSD -oslosphinx>=4.7.0 # Apache-2.0 -sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD stestr>=2.0.0 # Apache-2.0 -reno>=2.5.0 # Apache-2.0 -openstackdocstheme>=1.18.1 # Apache-2.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/tests/functional/test_swiftclient.py new/python-swiftclient-3.8.1/tests/functional/test_swiftclient.py --- old/python-swiftclient-3.7.0/tests/functional/test_swiftclient.py 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/tests/functional/test_swiftclient.py 2019-09-13 23:39:55.000000000 +0200 @@ -18,6 +18,7 @@ import time from io import BytesIO +import six from six.moves import configparser import swiftclient @@ -46,11 +47,34 @@ config.read(config_file) self.config = config if config.has_section('func_test'): - auth_host = config.get('func_test', 'auth_host') - auth_port = config.getint('func_test', 'auth_port') - auth_ssl = config.getboolean('func_test', 'auth_ssl') - auth_prefix = config.get('func_test', 'auth_prefix') - self.auth_version = config.get('func_test', 'auth_version') + if config.has_option('func_test', 'auth_uri'): + self.auth_url = config.get('func_test', 'auth_uri') + try: + self.auth_version = config.get('func_test', 'auth_version') + except configparser.NoOptionError: + last_piece = self.auth_url.rstrip('/').rsplit('/', 1)[1] + if last_piece.endswith('.0'): + last_piece = last_piece[:-2] + if last_piece in ('1', '2', '3'): + self.auth_version = last_piece + else: + raise + else: + auth_host = config.get('func_test', 'auth_host') + auth_port = config.getint('func_test', 'auth_port') + auth_ssl = config.getboolean('func_test', 'auth_ssl') + auth_prefix = config.get('func_test', 'auth_prefix') + self.auth_version = config.get('func_test', 'auth_version') + self.auth_url = "" + if auth_ssl: + self.auth_url += "https://" + else: + self.auth_url += "http://" + self.auth_url += "%s:%s%s" % ( + auth_host, auth_port, auth_prefix) + if self.auth_version == "1": + self.auth_url += 'v1.0' + try: self.account_username = config.get('func_test', 'account_username') @@ -59,15 +83,6 @@ username = config.get('func_test', 'username') self.account_username = "%s:%s" % (account, username) self.password = config.get('func_test', 'password') - self.auth_url = "" - if auth_ssl: - self.auth_url += "https://" - else: - self.auth_url += "http://" - self.auth_url += "%s:%s%s" % (auth_host, auth_port, auth_prefix) - if self.auth_version == "1": - self.auth_url += 'v1.0' - else: self.skip_tests = True @@ -432,6 +447,22 @@ self.assertEqual('45.67', headers.get('x-object-meta-float')) self.assertEqual('False', headers.get('x-object-meta-bool')) + def test_post_object_unicode_header_name(self): + self.conn.post_object(self.containername, + self.objectname, + {u'x-object-meta-\U0001f44d': u'\U0001f44d'}) + + # Note that we can't actually read this header back on py3; see + # https://bugs.python.org/issue37093 + # We'll have to settle for just testing that the POST doesn't blow up + # with a UnicodeDecodeError + if six.PY2: + headers = self.conn.head_object( + self.containername, self.objectname) + self.assertIn(u'x-object-meta-\U0001f44d', headers) + self.assertEqual(u'\U0001f44d', + headers.get(u'x-object-meta-\U0001f44d')) + def test_copy_object(self): self.conn.put_object( self.containername, self.objectname, self.test_data) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/tests/unit/test_service.py new/python-swiftclient-3.8.1/tests/unit/test_service.py --- old/python-swiftclient-3.7.0/tests/unit/test_service.py 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/tests/unit/test_service.py 2019-09-13 23:39:55.000000000 +0200 @@ -312,8 +312,8 @@ s = SwiftService() r = s._delete_object(mock_conn, 'test_c', 'test_o', self.opts, mock_q) - mock_conn.head_object.assert_called_once_with('test_c', 'test_o', - headers={}) + mock_conn.head_object.assert_called_once_with( + 'test_c', 'test_o', query_string='symlink=get', headers={}) mock_conn.delete_object.assert_called_once_with( 'test_c', 'test_o', query_string=None, response_dict={}, headers={} @@ -335,7 +335,8 @@ r = s._delete_object(mock_conn, 'test_c', 'test_o', opt_c, mock_q) mock_conn.head_object.assert_called_once_with( - 'test_c', 'test_o', headers={'Skip-Middleware': 'Test'}) + 'test_c', 'test_o', headers={'Skip-Middleware': 'Test'}, + query_string='symlink=get') mock_conn.delete_object.assert_called_once_with( 'test_c', 'test_o', query_string=None, response_dict={}, headers={'Skip-Middleware': 'Test'} @@ -362,8 +363,8 @@ r = s._delete_object(mock_conn, 'test_c', 'test_o', self.opts, mock_q) after = time.time() - mock_conn.head_object.assert_called_once_with('test_c', 'test_o', - headers={}) + mock_conn.head_object.assert_called_once_with( + 'test_c', 'test_o', query_string='symlink=get', headers={}) mock_conn.delete_object.assert_called_once_with( 'test_c', 'test_o', query_string=None, response_dict={}, headers={} @@ -389,8 +390,8 @@ s = SwiftService() r = s._delete_object(mock_conn, 'test_c', 'test_o', self.opts, mock_q) - mock_conn.head_object.assert_called_once_with('test_c', 'test_o', - headers={}) + mock_conn.head_object.assert_called_once_with( + 'test_c', 'test_o', query_string='symlink=get', headers={}) mock_conn.delete_object.assert_called_once_with( 'test_c', 'test_o', query_string='multipart-manifest=delete', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/tests/unit/test_shell.py new/python-swiftclient-3.8.1/tests/unit/test_shell.py --- old/python-swiftclient-3.7.0/tests/unit/test_shell.py 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/tests/unit/test_shell.py 2019-09-13 23:39:55.000000000 +0200 @@ -298,6 +298,26 @@ headers={'Skip-Middleware': 'Test'})]) @mock.patch('swiftclient.service.Connection') + def test_list_json(self, connection): + connection.return_value.get_account.side_effect = [ + [None, [{'name': 'container'}]], + [None, [{'name': u'\u263A', 'some-custom-key': 'and value'}]], + [None, []], + ] + + argv = ["", "list", "--json"] + with CaptureOutput(suppress_systemexit=True) as output: + swiftclient.shell.main(argv) + calls = [mock.call(marker='', prefix=None, headers={}), + mock.call(marker='container', prefix=None, headers={})] + connection.return_value.get_account.assert_has_calls(calls) + + listing = [{'name': 'container'}, + {'name': u'\u263A', 'some-custom-key': 'and value'}] + expected = json.dumps(listing, sort_keys=True, indent=2) + '\n' + self.assertEqual(output.out, expected) + + @mock.patch('swiftclient.service.Connection') def test_list_account(self, connection): # Test account listing connection.return_value.get_account.side_effect = [ @@ -799,11 +819,11 @@ response_dict={}) expected_delete_calls = [ mock.call( - b'container1', b'old_seg1', + 'container1', 'old_seg1', response_dict={} ), mock.call( - b'container2', b'old_seg2', + 'container2', 'old_seg2', response_dict={} ) ] @@ -813,6 +833,35 @@ ) @mock.patch('swiftclient.service.Connection') + def test_upload_over_symlink_to_slo(self, connection): + # Upload delete existing segments + connection.return_value.head_container.return_value = { + 'x-storage-policy': 'one'} + connection.return_value.attempts = 0 + connection.return_value.head_object.side_effect = [ + {'x-static-large-object': 'true', + 'content-location': '/v1/a/c/manifest', + 'content-length': '2'}, + ] + connection.return_value.get_object.return_value = ( + {'content-location': '/v1/a/c/manifest'}, + b'[{"name": "container1/old_seg1"},' + b' {"name": "container2/old_seg2"}]' + ) + connection.return_value.put_object.return_value = EMPTY_ETAG + connection.return_value.delete_object.return_value = None + argv = ["", "upload", "container", self.tmpfile] + swiftclient.shell.main(argv) + connection.return_value.put_object.assert_called_with( + 'container', + self.tmpfile.lstrip('/'), + mock.ANY, + content_length=0, + headers={'x-object-meta-mtime': mock.ANY}, + response_dict={}) + self.assertEqual([], connection.return_value.delete_object.mock_calls) + + @mock.patch('swiftclient.service.Connection') def test_upload_leave_slo_segments(self, connection): # Test upload overwriting a manifest respects --leave-segments connection.return_value.head_container.return_value = { @@ -835,6 +884,46 @@ self.assertFalse(connection.return_value.delete_object.mock_calls) @mock.patch('swiftclient.service.Connection') + def test_reupload_leaves_slo_segments(self, connection): + with open(self.tmpfile, "wb") as fh: + fh.write(b'12345678901234567890') + mtime = '{:.6f}'.format(os.path.getmtime(self.tmpfile)) + expected_segments = [ + 'container_segments/{}/slo/{}/20/10/{:08d}'.format( + self.tmpfile[1:], mtime, i) + for i in range(2) + ] + + # Test re-upload overwriting a manifest doesn't remove + # segments it just wrote + connection.return_value.head_container.return_value = { + 'x-storage-policy': 'one'} + connection.return_value.attempts = 0 + argv = ["", "upload", "container", self.tmpfile, + "--use-slo", "-S", "10"] + connection.return_value.head_object.side_effect = [ + {'x-static-large-object': 'true', # For the upload call + 'content-length': '20'}] + connection.return_value.get_object.return_value = ( + {}, + # we've already *got* the expected manifest! + json.dumps([ + {'name': seg} for seg in expected_segments + ]).encode('ascii') + ) + connection.return_value.put_object.return_value = ( + 'd41d8cd98f00b204e9800998ecf8427e') + swiftclient.shell.main(argv) + connection.return_value.put_object.assert_called_with( + 'container', + self.tmpfile[1:], # drop leading / + mock.ANY, + headers={'x-object-meta-mtime': mtime}, + query_string='multipart-manifest=put', + response_dict={}) + self.assertFalse(connection.return_value.delete_object.mock_calls) + + @mock.patch('swiftclient.service.Connection') def test_upload_delete_dlo_segments(self, connection): # Upload delete existing segments connection.return_value.head_container.return_value = { @@ -1822,7 +1911,7 @@ argv = ["", "tempurl", "GET", "60", '/v1/a/c', "secret_key", "--absolute", '--prefix-based'] with CaptureOutput(suppress_systemexit=True) as output: - swiftclient.shell.main(argv) + swiftclient.shell.main(argv) self.assertEqual(expected, output.err, 'Expected %r but got %r for path %r' % (expected, output.err, '/v1/a/c')) @@ -1832,7 +1921,7 @@ argv = ["", "tempurl", "GET", bad_time, '/v1/a/c/o', "secret_key", "--absolute"] with CaptureOutput(suppress_systemexit=True) as output: - swiftclient.shell.main(argv) + swiftclient.shell.main(argv) self.assertEqual(expected, output.err, 'Expected %r but got %r for time %r' % (expected, output.err, bad_time)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/tests/unit/test_utils.py new/python-swiftclient-3.8.1/tests/unit/test_utils.py --- old/python-swiftclient-3.7.0/tests/unit/test_utils.py 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/tests/unit/test_utils.py 2019-09-13 23:39:55.000000000 +0200 @@ -14,6 +14,7 @@ # limitations under the License. import gzip +import json import unittest import mock import six @@ -638,3 +639,41 @@ {'content-encoding': 'gzip'}, buf.getvalue()) self.assertEqual({'test': u'\u2603'}, result) + + +class JSONTracker(object): + def __init__(self, data): + self.data = data + self.calls = [] + + def __iter__(self): + for item in self.data: + self.calls.append(('read', item)) + yield item + + def write(self, s): + self.calls.append(('write', s)) + + +class TestJSONableIterable(unittest.TestCase): + def test_json_dump_iterencodes(self): + t = JSONTracker([1, 'fish', 2, 'fish']) + json.dump(u.JSONableIterable(t), t) + self.assertEqual(t.calls, [ + ('read', 1), + ('write', '[1'), + ('read', 'fish'), + ('write', ', "fish"'), + ('read', 2), + ('write', ', 2'), + ('read', 'fish'), + ('write', ', "fish"'), + ('write', ']'), + ]) + + def test_json_dump_empty_iter(self): + t = JSONTracker([]) + json.dump(u.JSONableIterable(t), t) + self.assertEqual(t.calls, [ + ('write', '[]'), + ]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/tests/unit/utils.py new/python-swiftclient-3.8.1/tests/unit/utils.py --- old/python-swiftclient-3.7.0/tests/unit/utils.py 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/tests/unit/utils.py 2019-09-13 23:39:55.000000000 +0200 @@ -20,6 +20,7 @@ import unittest import mock import six +import os from six.moves import reload_module from six.moves.urllib.parse import urlparse, ParseResult from swiftclient import client as c @@ -212,7 +213,19 @@ # won't cover the references to sys.stdout/sys.stderr in # swiftclient.multithreading self.capture_output = CaptureOutput() - self.capture_output.__enter__() + if 'SWIFTCLIENT_DEBUG' not in os.environ: + self.capture_output.__enter__() + self.addCleanup(self.capture_output.__exit__) + + # since we're going to steal all stderr output globally; we should + # give the developer an escape hatch or risk scorn + def blowup_but_with_the_helpful(*args, **kwargs): + raise Exception( + "You tried to enter a debugger while stderr is " + "patched, you need to set SWIFTCLIENT_DEBUG=1 " + "and try again") + import pdb + pdb.set_trace = blowup_but_with_the_helpful def fake_http_connection(*args, **kwargs): self.validateMockedRequestsConsumed() @@ -391,7 +404,6 @@ # un-hygienic mocking on the swiftclient.client module; which may lead # to some unfortunate test order dependency bugs by way of the broken # window theory if any other modules are similarly patched - self.capture_output.__exit__() reload_module(c) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-swiftclient-3.7.0/tox.ini new/python-swiftclient-3.8.1/tox.ini --- old/python-swiftclient-3.7.0/tox.ini 2019-03-05 14:10:18.000000000 +0100 +++ new/python-swiftclient-3.8.1/tox.ini 2019-09-13 23:39:55.000000000 +0200 @@ -1,5 +1,5 @@ [tox] -envlist = py37,py36,py35,py27,pypy,pep8 +envlist = py27,py37,pypy,pep8 minversion = 2.0 skipsdist = True @@ -65,8 +65,10 @@ [testenv:docs] basepython = python3 +usedevelop = False +deps = -r{toxinidir}/doc/requirements.txt commands= - python setup.py build_sphinx + python setup.py build_sphinx -W [flake8] # it's not a bug that we aren't using all of hacking, ignore: @@ -77,7 +79,11 @@ # H403: multi line docstrings should end on a new line # H404: multi line docstring should start without a leading new line # H405: multi line docstring summary not separated with an empty line -ignore = E731,H101,H301,H306,H401,H403,H404,H405 +# W504: line break after binary operator +ignore = H101,H301,H306,H401,H403,H404,H405,W504 +# H106: Don’t put vim configuration in source files +# H203: Use assertIs(Not)None to check for None +enable-extensions=H106,H203 show-source = True exclude = .venv,.tox,dist,doc,*egg @@ -93,6 +99,8 @@ [testenv:releasenotes] basepython = python3 +usedevelop = False +deps = -r{toxinidir}/doc/requirements.txt commands = sphinx-build -a -W -E -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html [testenv:lower-constraints] @@ -101,3 +109,12 @@ -c{toxinidir}/lower-constraints.txt -r{toxinidir}/test-requirements.txt .[keystone] + +[testenv:pdf-docs] +basepython = python3 +deps = {[testenv:docs]deps} +whitelist_externals = + make +commands = + sphinx-build -W -b latex doc/source doc/build/pdf + make -C doc/build/pdf