Enhance put_object to inform when chunk is ignored

Changed documentation for chunk_size parameter to indicate
that it can be used only with file like objects.

Also added a UserWarning when using a string contents to inform
that chunk_size will be ignored.

Added a unit test to check whether the warning is working
correctly.

Fixes: bug #1147232
Change-Id: I618ec45520ba81905ce2ead4d61f192d21ae3489
This commit is contained in:
jola-mirecka 2013-03-05 16:56:02 +00:00
parent 999e1c0f02
commit d90b768e50
2 changed files with 33 additions and 3 deletions

@ -21,6 +21,7 @@ import socket
import os
import sys
import logging
import warnings
from functools import wraps
from urllib import quote as _quote
@ -764,7 +765,7 @@ def head_object(url, token, container, name, http_conn=None):
def put_object(url, token=None, container=None, name=None, contents=None,
content_length=None, etag=None, chunk_size=65536,
content_length=None, etag=None, chunk_size=None,
content_type=None, headers=None, http_conn=None, proxy=None):
"""
Put an object
@ -782,7 +783,9 @@ def put_object(url, token=None, container=None, name=None, contents=None,
computed via the contents or chunked transfer
encoding will be used
:param etag: etag of contents; if None, no etag will be sent
:param chunk_size: chunk size of data to write; default 65536
:param chunk_size: chunk size of data to write; it defaults to 65536;
used only if the the contents object has a 'read'
method, eg. file-like objects, ignored otherwise
:param content_type: value to send as content-type header; if None, no
content-type will be set (remote end will likely try
to auto-detect it)
@ -822,6 +825,8 @@ def put_object(url, token=None, container=None, name=None, contents=None,
if not contents:
headers['Content-Length'] = '0'
if hasattr(contents, 'read'):
if chunk_size is None:
chunk_size = 65536
conn.putrequest('PUT', path)
for header, value in headers.iteritems():
conn.putheader(header, value)
@ -844,6 +849,10 @@ def put_object(url, token=None, container=None, name=None, contents=None,
conn.send(chunk)
left -= len(chunk)
else:
if chunk_size is not None:
warn_msg = '%s object has no \"read\" method, ignoring chunk_size'\
% type(contents).__name__
warnings.warn(warn_msg, stacklevel=2)
conn.request('PUT', path, contents, headers)
resp = conn.getresponse()
body = resp.read()
@ -1082,7 +1091,7 @@ class Connection(object):
resp_chunk_size=resp_chunk_size)
def put_object(self, container, obj, contents, content_length=None,
etag=None, chunk_size=65536, content_type=None,
etag=None, chunk_size=None, content_type=None,
headers=None):
"""Wrapper for :func:`put_object`"""

@ -17,6 +17,7 @@
import socket
import StringIO
import testtools
import warnings
from urlparse import urlparse
# TODO: mock http connection class with more control over headers
@ -472,6 +473,26 @@ class TestPutObject(MockHttpTest):
self.assertTrue("a-b: .x:yz mn:fg:lp" in resp.buffer[0],
"[a-b: .x:yz mn:fg:lp] header is missing")
def test_chunk_warning(self):
conn = c.http_connection('http://www.test.com/')
file = StringIO.StringIO('asdf')
args = ('asdf', 'asdf', 'asdf', 'asdf', file)
resp = MockHttpResponse()
conn[1].getresponse = resp.fake_response
conn[1].send = resp.fake_send
with warnings.catch_warnings(record=True) as w:
c.put_object(*args, chunk_size=20, headers={}, http_conn=conn)
self.assertEquals(len(w), 0)
body = 'c' * 60
c.http_connection = self.fake_http_connection(200, body=body)
args = ('http://www.test.com', 'asdf', 'asdf', 'asdf', 'asdf')
with warnings.catch_warnings(record=True) as w:
c.put_object(*args, chunk_size=20)
self.assertEquals(len(w), 1)
self.assertTrue(issubclass(w[-1].category, UserWarning))
def test_server_error(self):
body = 'c' * 60
c.http_connection = self.fake_http_connection(500, body=body)