launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #25495
[Merge] ~cjwatson/launchpad:py3-librarian-stringio into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:py3-librarian-stringio into launchpad:master.
Commit message:
Port librarian tests away from (c)StringIO.StringIO
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/392178
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:py3-librarian-stringio into launchpad:master.
diff --git a/lib/lp/services/librarian/doc/librarian.txt b/lib/lp/services/librarian/doc/librarian.txt
index 01f7ef9..6bb7a87 100644
--- a/lib/lp/services/librarian/doc/librarian.txt
+++ b/lib/lp/services/librarian/doc/librarian.txt
@@ -38,10 +38,10 @@ setUp
High Level
----------
- >>> from StringIO import StringIO
+ >>> import io
>>> from lp.services.librarian.interfaces import (
... ILibraryFileAliasSet)
- >>> data = 'This is some data'
+ >>> data = b'This is some data'
We can create LibraryFileAliases using the ILibraryFileAliasSet utility.
This name is a mouthful, but is consistent with the rest of our naming.
@@ -49,13 +49,13 @@ This name is a mouthful, but is consistent with the rest of our naming.
>>> lfas = getUtility(ILibraryFileAliasSet)
>>> from lp.services.librarian.interfaces import NEVER_EXPIRES
>>> alias = lfas.create(
- ... 'text.txt', len(data), StringIO(data), 'text/plain', NEVER_EXPIRES
- ... )
- >>> alias.mimetype
- u'text/plain'
+ ... 'text.txt', len(data), io.BytesIO(data), 'text/plain',
+ ... NEVER_EXPIRES)
+ >>> print(alias.mimetype)
+ text/plain
- >>> alias.filename
- u'text.txt'
+ >>> print(alias.filename)
+ text.txt
We may wish to set an expiry timestamp on the file. The NEVER_EXPIRES
constant means the file will never be removed from the Librarian, and
@@ -65,7 +65,7 @@ because of this should probably never be used.
True
>>> alias = lfas.create(
- ... 'text.txt', len(data), StringIO(data), 'text/plain')
+ ... 'text.txt', len(data), io.BytesIO(data), 'text/plain')
The default expiry of None means the file will expire a few days after
it is no longer referenced in the database.
@@ -149,7 +149,7 @@ files.
>>> transaction.commit()
>>> alias.open()
- >>> alias.read()
+ >>> six.ensure_str(alias.read())
'This is some data'
>>> alias.close()
@@ -157,13 +157,13 @@ files.
We can also read it in chunks.
>>> alias.open()
- >>> alias.read(2)
+ >>> six.ensure_str(alias.read(2))
'Th'
- >>> alias.read(6)
+ >>> six.ensure_str(alias.read(6))
'is is '
- >>> alias.read()
+ >>> six.ensure_str(alias.read())
'some data'
>>> alias.close()
@@ -171,7 +171,7 @@ We can also read it in chunks.
If you don't want to read the file in chunks you can neglect to call
open() and close().
- >>> alias.read()
+ >>> six.ensure_str(alias.read())
'This is some data'
Each alias also has an expiry date associated with it, the default of
@@ -197,11 +197,11 @@ access files in the Librarian.
>>> from lp.services.librarian.interfaces.client import ILibrarianClient
>>> client = getUtility(ILibrarianClient)
>>> aid = client.addFile(
- ... 'text.txt', len(data), StringIO(data), 'text/plain', NEVER_EXPIRES
- ... )
+ ... 'text.txt', len(data), io.BytesIO(data), 'text/plain',
+ ... NEVER_EXPIRES)
>>> transaction.commit()
>>> f = client.getFileByAlias(aid)
- >>> f.read()
+ >>> six.ensure_str(f.read())
'This is some data'
>>> url = client.getURLForAlias(aid)
@@ -248,18 +248,18 @@ rolls back. However, the records in the database will not be visible to
the client until it begins a new transaction.
>>> url = client.remoteAddFile(
- ... 'text.txt', len(data), StringIO(data), 'text/plain')
- >>> print url
+ ... 'text.txt', len(data), io.BytesIO(data), 'text/plain')
+ >>> print(url)
http://.../text.txt
>>> from six.moves.urllib.request import urlopen
- >>> urlopen(url).read()
+ >>> six.ensure_str(urlopen(url).read())
'This is some data'
If we abort the transaction, it is still in there
>>> transaction.abort()
- >>> urlopen(url).read()
+ >>> six.ensure_str(urlopen(url).read())
'This is some data'
You can also set the expiry date on the file this way too:
@@ -267,7 +267,7 @@ You can also set the expiry date on the file this way too:
>>> from datetime import date, datetime
>>> from pytz import utc
>>> url = client.remoteAddFile(
- ... 'text.txt', len(data), StringIO(data), 'text/plain',
+ ... 'text.txt', len(data), io.BytesIO(data), 'text/plain',
... expires=datetime(2005,9,1,12,0,0, tzinfo=utc))
>>> transaction.abort()
@@ -280,7 +280,7 @@ because, except for test cases, the URL is the only thing useful
>>> match = re.search('/(\d+)/', url)
>>> alias_id = int(match.group(1))
>>> alias = lfas[alias_id]
- >>> print alias.expires.isoformat()
+ >>> print(alias.expires.isoformat())
2005-09-01T12:00:00+00:00
@@ -305,9 +305,9 @@ librarian.
File alias uploaded through the restricted librarian have the restricted
attribute set.
- >>> private_content = 'This is private data.'
+ >>> private_content = b'This is private data.'
>>> private_file_id = restricted_client.addFile(
- ... 'private.txt', len(private_content), StringIO(private_content),
+ ... 'private.txt', len(private_content), io.BytesIO(private_content),
... 'text/plain')
>>> file_alias = getUtility(ILibraryFileAliasSet)[private_file_id]
>>> file_alias.restricted
@@ -315,14 +315,14 @@ attribute set.
>>> transaction.commit()
>>> file_alias.open()
- >>> print file_alias.read()
+ >>> print(six.ensure_str(file_alias.read()))
This is private data.
>>> file_alias.close()
Restricted files are accessible with HTTP on a private domain.
- >>> print file_alias.http_url
+ >>> print(file_alias.http_url)
http://.../private.txt
>>> file_alias.http_url.startswith(
@@ -336,7 +336,7 @@ provide such a token.
>>> import hashlib
>>> token_url = file_alias.getURL(include_token=True)
- >>> print token_url
+ >>> print(token_url)
https://i...restricted.../private.txt?token=...
>>> token_url.startswith('https://i%d.restricted.' % file_alias.id)
@@ -379,7 +379,7 @@ But using the restricted librarian will work:
<lp.services.librarian.client._File...>
>>> file_url = restricted_client.getURLForAlias(private_file_id)
- >>> print file_url
+ >>> print(file_url)
http://.../private.txt
Trying to access that file directly on the normal librarian will fail
@@ -395,15 +395,15 @@ Trying to access that file directly on the normal librarian will fail
But downloading it from the restricted host, will work.
- >>> print urlopen(file_url).read()
+ >>> print(six.ensure_str(urlopen(file_url).read()))
This is private data.
Trying to retrieve a non-restricted file from the restricted librarian
also fails:
- >>> public_content = 'This is public data.'
+ >>> public_content = b'This is public data.'
>>> public_file_id = getUtility(ILibrarianClient).addFile(
- ... 'public.txt', len(public_content), StringIO(public_content),
+ ... 'public.txt', len(public_content), io.BytesIO(public_content),
... 'text/plain')
>>> file_alias = getUtility(ILibraryFileAliasSet)[public_file_id]
>>> file_alias.restricted
@@ -426,8 +426,8 @@ file:
>>> url = restricted_client.remoteAddFile(
... 'another-private.txt', len(private_content),
- ... StringIO(private_content), 'text/plain')
- >>> print url
+ ... io.BytesIO(private_content), 'text/plain')
+ >>> print(url)
http://.../another-private.txt
>>> url.startswith(config.librarian.restricted_download_url)
@@ -435,7 +435,7 @@ file:
The file can then immediately be retrieved:
- >>> print urlopen(url).read()
+ >>> print(six.ensure_str(urlopen(url).read()))
This is private data.
Another way to create a restricted file is by using the restricted
@@ -443,7 +443,7 @@ parameter to ILibraryFileAliasSet:
>>> restricted_file = getUtility(ILibraryFileAliasSet).create(
... 'yet-another-private.txt', len(private_content),
- ... StringIO(private_content), 'text/plain', restricted=True)
+ ... io.BytesIO(private_content), 'text/plain', restricted=True)
>>> restricted_file.restricted
True
@@ -454,7 +454,7 @@ So searching for the private content on the public librarian will fail:
>>> transaction.commit()
>>> search_query = "search?digest=%s" % restricted_file.content.sha1
- >>> print urlopen(config.librarian.download_url + search_query).read()
+ >>> print(urlopen(config.librarian.download_url + search_query).read())
0
But on the restricted server, this will work:
@@ -462,7 +462,7 @@ But on the restricted server, this will work:
>>> result = urlopen(
... config.librarian.restricted_download_url + search_query).read()
>>> result = result.splitlines()
- >>> print result[0]
+ >>> print(result[0])
3
>>> sorted(file_path.split('/')[1] for file_path in result[1:])
@@ -475,7 +475,7 @@ Odds and Sods
An UploadFailed will be raised if you try to create a file with no
content
- >>> client.addFile('test.txt', 0, StringIO('hello'), 'text/plain')
+ >>> client.addFile('test.txt', 0, io.BytesIO(b'hello'), 'text/plain')
Traceback (most recent call last):
[...]
UploadFailed: Invalid length: 0
@@ -483,16 +483,16 @@ content
If you really want a zero length file you can do it:
>>> aid = client.addFile(
- ... 'test.txt', 0, StringIO(''), 'text/plain', allow_zero_length=True)
+ ... 'test.txt', 0, io.BytesIO(), 'text/plain', allow_zero_length=True)
>>> transaction.commit()
>>> f = client.getFileByAlias(aid)
- >>> f.read()
+ >>> six.ensure_str(f.read())
''
An AssertionError will be raised if the number of bytes that could be
read from the file don't match the declared size.
- >>> client.addFile('test.txt', 42, StringIO(''), 'text/plain')
+ >>> client.addFile('test.txt', 42, io.BytesIO(), 'text/plain')
Traceback (most recent call last):
[...]
AssertionError: size is 42, but 0 were read from the file
@@ -500,10 +500,10 @@ read from the file don't match the declared size.
Filenames with spaces in them work.
>>> aid = client.addFile(
- ... 'hot dog', len(data), StringIO(data), 'text/plain')
+ ... 'hot dog', len(data), io.BytesIO(data), 'text/plain')
>>> transaction.commit()
>>> f = client.getFileByAlias(aid)
- >>> f.read()
+ >>> six.ensure_str(f.read())
'This is some data'
>>> url = client.getURLForAlias(aid)
@@ -514,10 +514,10 @@ Unicode file names work. Note that the filename in the resulting URL is
encoded as UTF-8.
>>> aid = client.addFile(
- ... u'Yow\N{INTERROBANG}', len(data), StringIO(data), 'text/plain')
+ ... u'Yow\N{INTERROBANG}', len(data), io.BytesIO(data), 'text/plain')
>>> transaction.commit()
>>> f = client.getFileByAlias(aid)
- >>> f.read()
+ >>> six.ensure_str(f.read())
'This is some data'
>>> url = client.getURLForAlias(aid)
@@ -554,7 +554,7 @@ URL.
>>> from lp.services.webapp.servers import LaunchpadTestRequest
>>> req = LaunchpadTestRequest()
>>> alias = lfas.create(
- ... 'text2.txt', len(data), StringIO(data), 'text/plain',
+ ... 'text2.txt', len(data), io.BytesIO(data), 'text/plain',
... NEVER_EXPIRES)
>>> transaction.commit()
>>> lfa_view = getMultiAdapter((alias, req), name='+index')
@@ -569,15 +569,15 @@ File views setup
We need some files to test different ways of accessing them.
>>> filename = 'public.txt'
- >>> content = 'PUBLIC'
+ >>> content = b'PUBLIC'
>>> public_file = getUtility(ILibraryFileAliasSet).create(
- ... filename, len(content), StringIO(content), 'text/plain',
+ ... filename, len(content), io.BytesIO(content), 'text/plain',
... NEVER_EXPIRES, restricted=False)
>>> filename = 'restricted.txt'
- >>> content = 'RESTRICTED'
+ >>> content = b'RESTRICTED'
>>> restricted_file = getUtility(ILibraryFileAliasSet).create(
- ... filename, len(content), StringIO(content), 'text/plain',
+ ... filename, len(content), io.BytesIO(content), 'text/plain',
... NEVER_EXPIRES, restricted=True)
# Create a new LibraryFileAlias not referencing any LibraryFileContent
@@ -595,7 +595,7 @@ Commit the just-created files.
>>> transaction.commit()
>>> deleted_file = getUtility(ILibraryFileAliasSet)[deleted_file.id]
- >>> print deleted_file.deleted
+ >>> print(deleted_file.deleted)
True
Clear out existing tokens.
@@ -610,10 +610,10 @@ The MD5 summary for a file can be downloaded. The text file contains the
hash and file name.
>>> view = create_view(public_file, '+md5')
- >>> print view.render()
+ >>> print(view.render())
cd0c6092d6a6874f379fe4827ed1db8b public.txt
- >>> print view.request.response.getHeader('Content-type')
+ >>> print(view.request.response.getHeader('Content-type'))
text/plain
@@ -712,9 +712,9 @@ downloaded.
>>> public_file.last_downloaded == today - last_downloaded_date
True
- >>> content = 'something'
+ >>> content = b'something'
>>> brand_new_file = getUtility(ILibraryFileAliasSet).create(
- ... 'new.txt', len(content), StringIO(content), 'text/plain',
+ ... 'new.txt', len(content), io.BytesIO(content), 'text/plain',
... NEVER_EXPIRES, restricted=False)
- >>> print brand_new_file.last_downloaded
+ >>> print(brand_new_file.last_downloaded)
None
diff --git a/lib/lp/services/librarian/smoketest.py b/lib/lp/services/librarian/smoketest.py
index 6415209..4391e0c 100644
--- a/lib/lp/services/librarian/smoketest.py
+++ b/lib/lp/services/librarian/smoketest.py
@@ -6,8 +6,8 @@
"""Perform simple librarian operations to verify the current configuration.
"""
-from cStringIO import StringIO
import datetime
+import io
import sys
import pytz
@@ -19,14 +19,14 @@ from lp.services.librarian.interfaces import ILibraryFileAliasSet
FILE_SIZE = 1024
-FILE_DATA = 'x' * FILE_SIZE
+FILE_DATA = b'x' * FILE_SIZE
FILE_LIFETIME = datetime.timedelta(hours=1)
def store_file(client):
expiry_date = datetime.datetime.now(pytz.UTC) + FILE_LIFETIME
file_id = client.addFile(
- 'smoke-test-file', FILE_SIZE, StringIO(FILE_DATA), 'text/plain',
+ 'smoke-test-file', FILE_SIZE, io.BytesIO(FILE_DATA), 'text/plain',
expires=expiry_date)
# To be able to retrieve the file, we must commit the current transaction.
transaction.commit()
diff --git a/lib/lp/services/librarian/tests/test_client.py b/lib/lp/services/librarian/tests/test_client.py
index 9c671cb..d7f3cba 100644
--- a/lib/lp/services/librarian/tests/test_client.py
+++ b/lib/lp/services/librarian/tests/test_client.py
@@ -1,8 +1,8 @@
# Copyright 2009-2020 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
-from cStringIO import StringIO
import hashlib
+import io
import os
import re
import socket
@@ -231,7 +231,7 @@ class LibrarianClientTestCase(TestCase):
# addFile should send the Database-Name header.
client = InstrumentedLibrarianClient()
client.addFile(
- 'sample.txt', 6, StringIO('sample'), 'text/plain')
+ 'sample.txt', 6, io.BytesIO(b'sample'), 'text/plain')
self.assertTrue(client.sentDatabaseName,
"Database-Name header not sent by addFile")
@@ -242,8 +242,8 @@ class LibrarianClientTestCase(TestCase):
# different process, we need to explicitly tell the DatabaseLayer to
# fully tear down and set up the database.
DatabaseLayer.force_dirty_database()
- client.remoteAddFile('sample.txt', 6, StringIO('sample'),
- 'text/plain')
+ client.remoteAddFile(
+ 'sample.txt', 6, io.BytesIO(b'sample'), 'text/plain')
self.assertTrue(client.sentDatabaseName,
"Database-Name header not sent by remoteAddFile")
@@ -254,7 +254,8 @@ class LibrarianClientTestCase(TestCase):
# Force the client to mis-report its database
client._getDatabaseName = lambda cur: 'wrong_database'
try:
- client.addFile('sample.txt', 6, StringIO('sample'), 'text/plain')
+ client.addFile(
+ 'sample.txt', 6, io.BytesIO(b'sample'), 'text/plain')
except UploadFailed as e:
msg = e.args[0]
self.assertTrue(
@@ -285,7 +286,8 @@ class LibrarianClientTestCase(TestCase):
# right after, while uploading the file).
self.assertRaisesRegex(
UploadFailed, 'Server said early: STORE 7 sample.txt',
- client.addFile, 'sample.txt', 7, StringIO('sample'), 'text/plain')
+ client.addFile,
+ 'sample.txt', 7, io.BytesIO(b'sample'), 'text/plain')
def test_addFile_uses_master(self):
# addFile is a write operation, so it should always use the
@@ -296,7 +298,7 @@ class LibrarianClientTestCase(TestCase):
ISlaveStore(LibraryFileAlias).close()
with SlaveDatabasePolicy():
alias_id = client.addFile(
- 'sample.txt', 6, StringIO('sample'), 'text/plain')
+ 'sample.txt', 6, io.BytesIO(b'sample'), 'text/plain')
transaction.commit()
f = client.getFileByAlias(alias_id)
self.assertEqual(f.read(), 'sample')
@@ -308,7 +310,7 @@ class LibrarianClientTestCase(TestCase):
# empty line following the headers.
client = InstrumentedLibrarianClient()
client.addFile(
- 'sample.txt', 0, StringIO(''), 'text/plain',
+ 'sample.txt', 0, io.BytesIO(b''), 'text/plain',
allow_zero_length=True)
# addFile() calls _sendHeader() three times and _sendLine()
# twice, but it does not check if the server responded
@@ -321,7 +323,7 @@ class LibrarianClientTestCase(TestCase):
# header line. It does _not_ do this check when it sends the
# empty line following the headers.
client = InstrumentedLibrarianClient()
- client.addFile('sample.txt', 4, StringIO('1234'), 'text/plain')
+ client.addFile('sample.txt', 4, io.BytesIO(b'1234'), 'text/plain')
# addFile() calls _sendHeader() three times and _sendLine()
# twice.
self.assertEqual(5, client.check_error_calls)
@@ -329,14 +331,14 @@ class LibrarianClientTestCase(TestCase):
def test_addFile_hashes(self):
# addFile() sets the MD5, SHA-1 and SHA-256 hashes on the
# LibraryFileContent record.
- data = 'i am some data'
+ data = b'i am some data'
md5 = hashlib.md5(data).hexdigest()
sha1 = hashlib.sha1(data).hexdigest()
sha256 = hashlib.sha256(data).hexdigest()
client = LibrarianClient()
lfa = LibraryFileAlias.get(
- client.addFile('file', len(data), StringIO(data), 'text/plain'))
+ client.addFile('file', len(data), io.BytesIO(data), 'text/plain'))
self.assertEqual(md5, lfa.content.md5)
self.assertEqual(sha1, lfa.content.sha1)
@@ -351,7 +353,7 @@ class LibrarianClientTestCase(TestCase):
# (Set up:)
client = LibrarianClient()
alias_id = client.addFile(
- 'sample.txt', 6, StringIO('sample'), 'text/plain')
+ 'sample.txt', 6, io.BytesIO(b'sample'), 'text/plain')
config.push(
'test config',
textwrap.dedent('''\
@@ -387,7 +389,7 @@ class LibrarianClientTestCase(TestCase):
# (Set up:)
client = RestrictedLibrarianClient()
alias_id = client.addFile(
- 'sample.txt', 6, StringIO('sample'), 'text/plain')
+ 'sample.txt', 6, io.BytesIO(b'sample'), 'text/plain')
config.push(
'test config',
textwrap.dedent('''\
@@ -421,7 +423,7 @@ class LibrarianClientTestCase(TestCase):
# (Set up:)
client = InstrumentedLibrarianClient()
alias_id = client.addFile(
- 'sample.txt', 6, StringIO('sample'), 'text/plain')
+ 'sample.txt', 6, io.BytesIO(b'sample'), 'text/plain')
transaction.commit() # Make sure the file is in the "remote" database.
self.assertFalse(client.called_getURLForDownload)
# (Test:)
@@ -439,7 +441,7 @@ class LibrarianClientTestCase(TestCase):
client = InstrumentedLibrarianClient()
alias_id = client.addFile(
- 'sample.txt', 6, StringIO('sample'), 'text/plain')
+ 'sample.txt', 6, io.BytesIO(b'sample'), 'text/plain')
transaction.commit()
self.assertRaises(LookupError, client.getFileByAlias, alias_id)
@@ -456,7 +458,7 @@ class LibrarianClientTestCase(TestCase):
HTTPError('http://fake.url/', 500, 'Forced error', None, None), 2)
client = InstrumentedLibrarianClient()
alias_id = client.addFile(
- 'sample.txt', 6, StringIO('sample'), 'text/plain')
+ 'sample.txt', 6, io.BytesIO(b'sample'), 'text/plain')
transaction.commit()
self.assertRaises(
LibrarianServerError, client.getFileByAlias, alias_id, 1)
@@ -465,7 +467,7 @@ class LibrarianClientTestCase(TestCase):
URLError('Connection refused'), 2)
client = InstrumentedLibrarianClient()
alias_id = client.addFile(
- 'sample.txt', 6, StringIO('sample'), 'text/plain')
+ 'sample.txt', 6, io.BytesIO(b'sample'), 'text/plain')
transaction.commit()
self.assertRaises(
LibrarianServerError, client.getFileByAlias, alias_id, 1)
@@ -482,7 +484,7 @@ class LibrarianClientTestCase(TestCase):
HTTPError('http://fake.url/', 500, 'Forced error', None, None), 1)
client = InstrumentedLibrarianClient()
alias_id = client.addFile(
- 'sample.txt', 6, StringIO('sample'), 'text/plain')
+ 'sample.txt', 6, io.BytesIO(b'sample'), 'text/plain')
transaction.commit()
self.assertEqual(
client.getFileByAlias(alias_id), 'This is a fake file object', 3)
@@ -491,7 +493,7 @@ class LibrarianClientTestCase(TestCase):
URLError('Connection refused'), 1)
client = InstrumentedLibrarianClient()
alias_id = client.addFile(
- 'sample.txt', 6, StringIO('sample'), 'text/plain')
+ 'sample.txt', 6, io.BytesIO(b'sample'), 'text/plain')
transaction.commit()
self.assertEqual(
client.getFileByAlias(alias_id), 'This is a fake file object', 3)
@@ -502,7 +504,7 @@ class LibrarianClientTestCase(TestCase):
client = InstrumentedLibrarianClient()
th = PropagatingThread(
target=client.addFile,
- args=('sample.txt', 6, StringIO('sample'), 'text/plain'))
+ args=('sample.txt', 6, io.BytesIO(b'sample'), 'text/plain'))
th.start()
th.join()
self.assertEqual(5, client.check_error_calls)
diff --git a/lib/lp/services/librarian/tests/test_libraryfilealias.py b/lib/lp/services/librarian/tests/test_libraryfilealias.py
index bacd931..0189feb 100644
--- a/lib/lp/services/librarian/tests/test_libraryfilealias.py
+++ b/lib/lp/services/librarian/tests/test_libraryfilealias.py
@@ -5,7 +5,7 @@
__metaclass__ = type
-from cStringIO import StringIO
+import io
import unittest
import transaction
@@ -25,10 +25,10 @@ class TestLibraryFileAlias(unittest.TestCase):
def setUp(self):
login(ANONYMOUS)
- self.text_content = "This is content\non two lines."
+ self.text_content = b"This is content\non two lines."
self.file_alias = getUtility(ILibraryFileAliasSet).create(
'content.txt', len(self.text_content),
- StringIO(self.text_content), 'text/plain')
+ io.BytesIO(self.text_content), 'text/plain')
# Make it posssible to retrieve the content from the Librarian.
transaction.commit()
diff --git a/lib/lp/services/librarian/tests/test_smoketest.py b/lib/lp/services/librarian/tests/test_smoketest.py
index 2134967..992cf38 100644
--- a/lib/lp/services/librarian/tests/test_smoketest.py
+++ b/lib/lp/services/librarian/tests/test_smoketest.py
@@ -7,10 +7,11 @@ from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
-from cStringIO import StringIO
from functools import partial
+import io
from fixtures import MockPatch
+import six
from lp.services.librarian.smoketest import (
do_smoketest,
@@ -24,12 +25,12 @@ from lp.testing.layers import ZopelessDatabaseLayer
def good_urlopen(url):
"""A urllib replacement for testing that returns good results."""
- return StringIO(FILE_DATA)
+ return io.BytesIO(FILE_DATA)
def bad_urlopen(url):
"""A urllib replacement for testing that returns bad results."""
- return StringIO('bad data')
+ return io.BytesIO(b'bad data')
def error_urlopen(url):
@@ -66,7 +67,7 @@ class SmokeTestTestCase(TestCaseWithFactory):
"lp.services.librarian.smoketest.urlopen", good_urlopen):
self.assertEqual(
do_smoketest(self.fake_librarian, self.fake_librarian,
- output=StringIO()),
+ output=six.StringIO()),
0)
def test_bad_data(self):
@@ -75,7 +76,7 @@ class SmokeTestTestCase(TestCaseWithFactory):
with MockPatch("lp.services.librarian.smoketest.urlopen", bad_urlopen):
self.assertEqual(
do_smoketest(self.fake_librarian, self.fake_librarian,
- output=StringIO()),
+ output=six.StringIO()),
1)
def test_exception(self):
@@ -86,7 +87,7 @@ class SmokeTestTestCase(TestCaseWithFactory):
"lp.services.librarian.smoketest.urlopen", error_urlopen):
self.assertEqual(
do_smoketest(self.fake_librarian, self.fake_librarian,
- output=StringIO()),
+ output=six.StringIO()),
1)
def test_explosive_errors(self):
@@ -99,4 +100,4 @@ class SmokeTestTestCase(TestCaseWithFactory):
self.assertRaises(
exception,
do_smoketest, self.fake_librarian, self.fake_librarian,
- output=StringIO())
+ output=six.StringIO())