Accept more types of input for headers/meta

Previously, we only accepted iterables of strings like 'Header: Value'.
Now, we'll also accept lists of tuples like ('Header', 'Value') as well
as dictionaries like {'Header': 'Value'}.

This should be more intuitive for application developers, who are
already used to being able to pass dicts or lists of tuples to libraries
like requests.

Change-Id: I93ed2f1e8305f0168b7a4bd90c205b04730da836
This commit is contained in:
Tim Burke 2016-08-23 16:17:21 -07:00
parent 12d42efad2
commit a1e2bcde4a
3 changed files with 37 additions and 12 deletions

View File

@ -29,11 +29,10 @@ from posixpath import join as urljoin
from random import shuffle from random import shuffle
from time import time from time import time
from threading import Thread from threading import Thread
from six import StringIO, text_type from six import Iterator, StringIO, string_types, text_type
from six.moves.queue import Queue from six.moves.queue import Queue
from six.moves.queue import Empty as QueueEmpty from six.moves.queue import Empty as QueueEmpty
from six.moves.urllib.parse import quote from six.moves.urllib.parse import quote
from six import Iterator, string_types
import json import json
@ -274,7 +273,10 @@ def split_headers(options, prefix=''):
""" """
Splits 'Key: Value' strings and returns them as a dictionary. Splits 'Key: Value' strings and returns them as a dictionary.
:param options: An array of 'Key: Value' strings :param options: Must be one of:
* an iterable of 'Key: Value' strings
* an iterable of ('Key', 'Value') pairs
* a dict of {'Key': 'Value'} pairs
:param prefix: String to prepend to all of the keys in the dictionary. :param prefix: String to prepend to all of the keys in the dictionary.
reporting. reporting.
""" """

View File

@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
"""Miscellaneous utility functions for use with Swift.""" """Miscellaneous utility functions for use with Swift."""
import collections
import gzip import gzip
import hashlib import hashlib
import hmac import hmac
@ -148,15 +149,24 @@ def parse_api_response(headers, body):
def split_request_headers(options, prefix=''): def split_request_headers(options, prefix=''):
headers = {} headers = {}
if isinstance(options, collections.Mapping):
options = options.items()
for item in options: for item in options:
split_item = item.split(':', 1) if isinstance(item, six.string_types):
if len(split_item) == 2: if ':' not in item:
headers[(prefix + split_item[0]).title()] = split_item[1].strip()
else:
raise ValueError( raise ValueError(
"Metadata parameter %s must contain a ':'.\n%s" "Metadata parameter %s must contain a ':'.\n"
% (item, "Example: 'Color:Blue' or 'Size:Large'") "Example: 'Color:Blue' or 'Size:Large'"
% item
) )
item = item.split(':', 1)
if len(item) != 2:
raise ValueError(
"Metadata parameter %r must have exactly two items.\n"
"Example: ('Color', 'Blue') or ['Size', 'Large']"
% (item, )
)
headers[(prefix + item[0]).title()] = item[1].strip()
return headers return headers

View File

@ -592,11 +592,24 @@ class TestServiceUtils(unittest.TestCase):
actual = swiftclient.service.split_headers(mock_headers, 'prefix-') actual = swiftclient.service.split_headers(mock_headers, 'prefix-')
self.assertEqual(expected, actual) self.assertEqual(expected, actual)
def test_split_headers_error(self): def test_split_headers_list_of_tuples(self):
mock_headers = ['notvalid'] mock_headers = [('color', 'blue'), ('size', 'large')]
expected = {'Prefix-Color': 'blue', 'Prefix-Size': 'large'}
actual = swiftclient.service.split_headers(mock_headers, 'prefix-')
self.assertEqual(expected, actual)
def test_split_headers_dict(self):
expected = {'Color': 'blue', 'Size': 'large'}
actual = swiftclient.service.split_headers(expected)
self.assertEqual(expected, actual)
def test_split_headers_error(self):
self.assertRaises(SwiftError, swiftclient.service.split_headers, self.assertRaises(SwiftError, swiftclient.service.split_headers,
mock_headers) ['notvalid'])
self.assertRaises(SwiftError, swiftclient.service.split_headers,
[('also', 'not', 'valid')])
class TestSwiftUploadObject(unittest.TestCase): class TestSwiftUploadObject(unittest.TestCase):