Merge "Always decode command-line arguments as UTF-8"
This commit is contained in:
commit
a56eac13b1
@ -14,7 +14,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import logging
|
||||
import signal
|
||||
@ -23,6 +23,7 @@ import socket
|
||||
from optparse import OptionParser, OptionGroup, SUPPRESS_HELP
|
||||
from os import environ, walk, _exit as os_exit
|
||||
from os.path import isfile, isdir, join
|
||||
from six import text_type
|
||||
from sys import argv as sys_argv, exit, stderr
|
||||
from time import gmtime, strftime
|
||||
|
||||
@ -111,7 +112,7 @@ def st_delete(parser, args, output_manager):
|
||||
if '/' in container:
|
||||
output_manager.error(
|
||||
'WARNING: / in container name; you '
|
||||
'might have meant %r instead of %r.' % (
|
||||
"might have meant '%s' instead of '%s'." % (
|
||||
container.replace('/', ' ', 1), container)
|
||||
)
|
||||
return
|
||||
@ -276,7 +277,7 @@ def st_download(parser, args, output_manager):
|
||||
if '/' in container:
|
||||
output_manager.error(
|
||||
'WARNING: / in container name; you '
|
||||
'might have meant %r instead of %r.' % (
|
||||
"might have meant '%s' instead of '%s'." % (
|
||||
container.replace('/', ' ', 1), container)
|
||||
)
|
||||
return
|
||||
@ -527,7 +528,7 @@ def st_stat(parser, args, output_manager):
|
||||
if '/' in container:
|
||||
output_manager.error(
|
||||
'WARNING: / in container name; you might have '
|
||||
'meant %r instead of %r.' %
|
||||
"meant '%s' instead of '%s'." %
|
||||
(container.replace('/', ' ', 1), container))
|
||||
return
|
||||
args = args[1:]
|
||||
@ -631,7 +632,7 @@ def st_post(parser, args, output_manager):
|
||||
if '/' in container:
|
||||
output_manager.error(
|
||||
'WARNING: / in container name; you might have '
|
||||
'meant %r instead of %r.' %
|
||||
"meant '%s' instead of '%s'." %
|
||||
(args[0].replace('/', ' ', 1), args[0]))
|
||||
return
|
||||
args = args[1:]
|
||||
@ -871,7 +872,7 @@ def st_upload(parser, args, output_manager):
|
||||
msg = ': %s' % error
|
||||
output_manager.warning(
|
||||
'Warning: failed to create container '
|
||||
'%r%s', container, msg
|
||||
"'%s'%s", container, msg
|
||||
)
|
||||
else:
|
||||
output_manager.error("%s" % error)
|
||||
@ -1104,6 +1105,8 @@ def main(arguments=None):
|
||||
else:
|
||||
argv = sys_argv
|
||||
|
||||
argv = [a if isinstance(a, text_type) else a.decode('utf-8') for a in argv]
|
||||
|
||||
version = client_version
|
||||
parser = OptionParser(version='python-swiftclient %s' % version,
|
||||
usage='''
|
||||
|
@ -12,6 +12,7 @@
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from __future__ import unicode_literals
|
||||
from genericpath import getmtime
|
||||
|
||||
import hashlib
|
||||
@ -657,6 +658,38 @@ class TestShell(unittest.TestCase):
|
||||
connection.return_value.delete_object.assert_called_with(
|
||||
'container', 'object', query_string=None, response_dict={})
|
||||
|
||||
def test_delete_verbose_output_utf8(self):
|
||||
container = 't\u00e9st_c'
|
||||
base_argv = ['', '--verbose', 'delete']
|
||||
|
||||
# simulate container having an object with utf-8 code points in name,
|
||||
# just returning the object delete result
|
||||
res = {'success': True, 'response_dict': {}, 'attempts': 2,
|
||||
'container': container, 'action': 'delete_object',
|
||||
'object': 'obj_t\u00east_o'}
|
||||
|
||||
with mock.patch('swiftclient.shell.SwiftService.delete') as mock_func:
|
||||
with CaptureOutput() as out:
|
||||
mock_func.return_value = [res]
|
||||
swiftclient.shell.main(base_argv + [container.encode('utf-8')])
|
||||
|
||||
mock_func.assert_called_once_with(container=container)
|
||||
self.assertTrue(out.out.find(
|
||||
'obj_t\u00east_o [after 2 attempts]') >= 0, out)
|
||||
|
||||
# simulate empty container
|
||||
res = {'success': True, 'response_dict': {}, 'attempts': 2,
|
||||
'container': container, 'action': 'delete_container'}
|
||||
|
||||
with mock.patch('swiftclient.shell.SwiftService.delete') as mock_func:
|
||||
with CaptureOutput() as out:
|
||||
mock_func.return_value = [res]
|
||||
swiftclient.shell.main(base_argv + [container.encode('utf-8')])
|
||||
|
||||
mock_func.assert_called_once_with(container=container)
|
||||
self.assertTrue(out.out.find(
|
||||
't\u00e9st_c [after 2 attempts]') >= 0, out)
|
||||
|
||||
@mock.patch('swiftclient.service.Connection')
|
||||
def test_delete_object(self, connection):
|
||||
argv = ["", "delete", "container", "object"]
|
||||
@ -668,8 +701,8 @@ class TestShell(unittest.TestCase):
|
||||
|
||||
def test_delete_verbose_output(self):
|
||||
del_obj_res = {'success': True, 'response_dict': {}, 'attempts': 2,
|
||||
'container': 'test_c', 'action': 'delete_object',
|
||||
'object': 'test_o'}
|
||||
'container': 't\xe9st_c', 'action': 'delete_object',
|
||||
'object': 't\xe9st_o'}
|
||||
|
||||
del_seg_res = del_obj_res.copy()
|
||||
del_seg_res.update({'action': 'delete_segment'})
|
||||
@ -677,7 +710,7 @@ class TestShell(unittest.TestCase):
|
||||
del_con_res = del_obj_res.copy()
|
||||
del_con_res.update({'action': 'delete_container', 'object': None})
|
||||
|
||||
test_exc = Exception('test_exc')
|
||||
test_exc = Exception('t\xe9st_exc')
|
||||
error_res = del_obj_res.copy()
|
||||
error_res.update({'success': False, 'error': test_exc, 'object': None})
|
||||
|
||||
@ -687,39 +720,39 @@ class TestShell(unittest.TestCase):
|
||||
with mock.patch('swiftclient.shell.SwiftService.delete', mock_delete):
|
||||
with CaptureOutput() as out:
|
||||
mock_delete.return_value = [del_obj_res]
|
||||
swiftclient.shell.main(base_argv + ['test_c', 'test_o'])
|
||||
swiftclient.shell.main(base_argv + ['t\xe9st_c', 't\xe9st_o'])
|
||||
|
||||
mock_delete.assert_called_once_with(container='test_c',
|
||||
objects=['test_o'])
|
||||
mock_delete.assert_called_once_with(container='t\xe9st_c',
|
||||
objects=['t\xe9st_o'])
|
||||
self.assertTrue(out.out.find(
|
||||
'test_o [after 2 attempts]') >= 0)
|
||||
't\xe9st_o [after 2 attempts]') >= 0)
|
||||
|
||||
with CaptureOutput() as out:
|
||||
mock_delete.return_value = [del_seg_res]
|
||||
swiftclient.shell.main(base_argv + ['test_c', 'test_o'])
|
||||
swiftclient.shell.main(base_argv + ['t\xe9st_c', 't\xe9st_o'])
|
||||
|
||||
mock_delete.assert_called_with(container='test_c',
|
||||
objects=['test_o'])
|
||||
mock_delete.assert_called_with(container='t\xe9st_c',
|
||||
objects=['t\xe9st_o'])
|
||||
self.assertTrue(out.out.find(
|
||||
'test_c/test_o [after 2 attempts]') >= 0)
|
||||
't\xe9st_c/t\xe9st_o [after 2 attempts]') >= 0)
|
||||
|
||||
with CaptureOutput() as out:
|
||||
mock_delete.return_value = [del_con_res]
|
||||
swiftclient.shell.main(base_argv + ['test_c'])
|
||||
swiftclient.shell.main(base_argv + ['t\xe9st_c'])
|
||||
|
||||
mock_delete.assert_called_with(container='test_c')
|
||||
mock_delete.assert_called_with(container='t\xe9st_c')
|
||||
self.assertTrue(out.out.find(
|
||||
'test_c [after 2 attempts]') >= 0)
|
||||
't\xe9st_c [after 2 attempts]') >= 0)
|
||||
|
||||
with CaptureOutput() as out:
|
||||
mock_delete.return_value = [error_res]
|
||||
self.assertRaises(SystemExit,
|
||||
swiftclient.shell.main,
|
||||
base_argv + ['test_c'])
|
||||
base_argv + ['t\xe9st_c'])
|
||||
|
||||
mock_delete.assert_called_with(container='test_c')
|
||||
mock_delete.assert_called_with(container='t\xe9st_c')
|
||||
self.assertTrue(out.err.find(
|
||||
'Error Deleting: test_c: test_exc') >= 0)
|
||||
'Error Deleting: t\xe9st_c: t\xe9st_exc') >= 0)
|
||||
|
||||
@mock.patch('swiftclient.service.Connection')
|
||||
def test_post_account(self, connection):
|
||||
@ -1738,7 +1771,7 @@ class TestCrossAccountObjectAccess(TestBase, MockHttpTest):
|
||||
self.assertRequests([('PUT', self.cont_path),
|
||||
('PUT', self.obj_path)])
|
||||
self.assertEqual(self.obj[1:], out.strip())
|
||||
expected_err = 'Warning: failed to create container %r: 403 Fake' \
|
||||
expected_err = "Warning: failed to create container '%s': 403 Fake" \
|
||||
% self.cont
|
||||
self.assertEqual(expected_err, out.err.strip())
|
||||
|
||||
@ -1760,7 +1793,7 @@ class TestCrossAccountObjectAccess(TestBase, MockHttpTest):
|
||||
self.assertRequests([('PUT', self.cont_path),
|
||||
('PUT', self.obj_path)])
|
||||
self.assertEqual(self.obj[1:], out.strip())
|
||||
expected_err = 'Warning: failed to create container %r: 403 Fake' \
|
||||
expected_err = "Warning: failed to create container '%s': 403 Fake" \
|
||||
% self.cont
|
||||
self.assertEqual(expected_err, out.err.strip())
|
||||
|
||||
@ -1795,7 +1828,7 @@ class TestCrossAccountObjectAccess(TestBase, MockHttpTest):
|
||||
self.assert_request(('PUT', segment_path_1))
|
||||
self.assert_request(('PUT', self.obj_path))
|
||||
self.assertTrue(self.obj[1:] in out.out)
|
||||
expected_err = 'Warning: failed to create container %r: 403 Fake' \
|
||||
expected_err = "Warning: failed to create container '%s': 403 Fake" \
|
||||
% self.cont
|
||||
self.assertEqual(expected_err, out.err.strip())
|
||||
|
||||
@ -1884,7 +1917,7 @@ class TestCrossAccountObjectAccess(TestBase, MockHttpTest):
|
||||
|
||||
self.assertRequests([('GET', self.obj_path)])
|
||||
path = '%s%s' % (self.cont, self.obj)
|
||||
expected_err = 'Error downloading object %r' % path
|
||||
expected_err = "Error downloading object '%s'" % path
|
||||
self.assertTrue(out.err.startswith(expected_err))
|
||||
self.assertEqual('', out)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user