launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #25775
[Merge] ~cjwatson/launchpad:librarianserver-future-imports into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:librarianserver-future-imports into launchpad:master.
Commit message:
Convert lp.services.librarianserver to preferred __future__ imports
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/394720
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:librarianserver-future-imports into launchpad:master.
diff --git a/lib/lp/services/librarianserver/apachelogparser.py b/lib/lp/services/librarianserver/apachelogparser.py
index 478bdab..8cce64f 100644
--- a/lib/lp/services/librarianserver/apachelogparser.py
+++ b/lib/lp/services/librarianserver/apachelogparser.py
@@ -1,6 +1,8 @@
# Copyright 2009 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
+from __future__ import absolute_import, print_function, unicode_literals
+
import re
@@ -8,17 +10,17 @@ DBUSER = 'librarianlogparser'
# Regexp used to match paths to LibraryFileAliases.
-lfa_path_re = re.compile('^/[0-9]+/')
-multi_slashes_re = re.compile('/+')
+lfa_path_re = re.compile(br'^/[0-9]+/')
+multi_slashes_re = re.compile(br'/+')
def get_library_file_id(path):
- path = multi_slashes_re.sub('/', path)
+ path = multi_slashes_re.sub(b'/', path)
if not lfa_path_re.match(path):
# We only count downloads of LibraryFileAliases, and this is
# not one of them.
return None
- file_id = path.split('/')[1]
+ file_id = path.split(b'/')[1]
assert file_id.isdigit(), ('File ID is not a digit: %s' % path)
- return file_id
+ return file_id.decode('UTF-8')
diff --git a/lib/lp/services/librarianserver/db.py b/lib/lp/services/librarianserver/db.py
index dc59db5..41119df 100644
--- a/lib/lp/services/librarianserver/db.py
+++ b/lib/lp/services/librarianserver/db.py
@@ -3,6 +3,8 @@
"""Database access layer for the Librarian."""
+from __future__ import absolute_import, print_function, unicode_literals
+
__metaclass__ = type
__all__ = [
'Library',
diff --git a/lib/lp/services/librarianserver/doc/librarian-report.txt b/lib/lp/services/librarianserver/doc/librarian-report.txt
index 3270ea6..1c11b0f 100644
--- a/lib/lp/services/librarianserver/doc/librarian-report.txt
+++ b/lib/lp/services/librarianserver/doc/librarian-report.txt
@@ -5,10 +5,10 @@ storage.
>>> script = 'scripts/librarian-report.py'
>>> rv, out, err = run_script(script)
- >>> print rv
+ >>> print(rv)
0
- >>> print err
- >>> print '\n' + out
+ >>> print(err)
+ >>> print('\n' + out)
<BLANKLINE>
...
4866 bytes hwsubmission in 2 files
@@ -19,13 +19,11 @@ We can filter on date to produce deltas.
>>> rv, out, err = run_script(
... script, ['--from=2005/01/01', '--until=2005/12/31'])
- >>> print rv
+ >>> print(rv)
0
- >>> print err
- >>> print '\n' + out
+ >>> print(err)
+ >>> print('\n' + out)
<BLANKLINE>
...
0 bytes hwsubmission in 0 files
...
-
-
diff --git a/lib/lp/services/librarianserver/doc/upload.txt b/lib/lp/services/librarianserver/doc/upload.txt
index 562ea5f..ca8c26a 100644
--- a/lib/lp/services/librarianserver/doc/upload.txt
+++ b/lib/lp/services/librarianserver/doc/upload.txt
@@ -11,7 +11,7 @@ Database check
The Database-Name header is now mandatory. If it isn't present, an otherwise
well-formed request will be rejected:
- >>> upload_request("""STORE 14 hello.txt
+ >>> upload_request(b"""STORE 14 hello.txt
... Content-Type: text/plain
... File-Content-ID: 123
... File-Alias-ID: 456
@@ -23,7 +23,7 @@ well-formed request will be rejected:
If Database-Name is specified by the client, and doesn't match the database name
of the server, the upload is rejected.
- >>> upload_request("""STORE 14 hello.txt
+ >>> upload_request(b"""STORE 14 hello.txt
... Content-Type: text/plain
... File-Content-ID: 123
... File-Alias-ID: 456
@@ -35,7 +35,7 @@ of the server, the upload is rejected.
If the database name matches, it's accepted as usual.
- >>> upload_request("""STORE 14 hello.txt
+ >>> upload_request(b"""STORE 14 hello.txt
... Content-Type: text/plain
... File-Content-ID: 123
... File-Alias-ID: 456
@@ -43,7 +43,7 @@ If the database name matches, it's accepted as usual.
...
... Cats and dogs.""")
reply: '200'
- file u'hello.txt' stored as text/plain, contents: 'Cats and dogs.'
+ file 'hello.txt' stored as text/plain, contents: 'Cats and dogs.'
Error conditions
@@ -52,39 +52,39 @@ Error conditions
Errors receive a 400 status code in the reply, and the connection will be
closed.
+Invalid UTF-8 lines are rejected.
+
+ >>> upload_request(b"STORE 10000 \xff\n")
+ reply: '400 Non-data lines must be in UTF-8'
+ connection closed
+
Unknown commands are rejected.
- >>> upload_request("FROB the chicken\n")
+ >>> upload_request(b"FROB the chicken\n")
reply: '400 Unknown command: FROB the chicken'
connection closed
Incomplete STORE commands are rejected.
- >>> upload_request("STORE bad-arg!\n")
+ >>> upload_request(b"STORE bad-arg!\n")
reply: '400 STORE command expects a size and file name'
connection closed
Invalid headers are rejected.
- >>> upload_request("""STORE 10000 foo.txt
+ >>> upload_request(b"""STORE 10000 foo.txt
... Some garbage.
... """)
reply: '400 Invalid header: Some garbage.'
connection closed
-Invalid UTF-8 filenames are rejected.
-
- >>> upload_request("STORE 10000 \xff\n")
- reply: '400 STORE command expects the filename to be in UTF-8'
- connection closed
-
Uploading corner cases
----------------------
Empty files work, rather than hang the connection.
- >>> upload_request("""STORE 0 foo.txt
+ >>> upload_request(b"""STORE 0 foo.txt
... Content-Type: text/plain
... File-Content-ID: 123
... File-Alias-ID: 456
@@ -92,11 +92,11 @@ Empty files work, rather than hang the connection.
...
... """)
reply: '200'
- file u'foo.txt' stored as text/plain, contents: ''
+ file 'foo.txt' stored as text/plain, contents: ''
Filename with spaces work.
- >>> upload_request("""STORE 14 cats and dogs.txt
+ >>> upload_request(b"""STORE 14 cats and dogs.txt
... Content-Type: text/plain
... File-Content-ID: 123
... File-Alias-ID: 456
@@ -104,12 +104,12 @@ Filename with spaces work.
...
... Cats and dogs.""")
reply: '200'
- file u'cats and dogs.txt' stored as text/plain, contents: 'Cats and dogs.'
+ file 'cats and dogs.txt' stored as text/plain, contents: 'Cats and dogs.'
Unicode filenames work, but must be encoded as UTF-8 on the socket.
- >>> filename = u'Yow\N{INTERROBANG}'.encode('utf-8')
- >>> upload_request("""STORE 14 %s
+ >>> filename = 'Yow\N{INTERROBANG}'.encode('utf-8')
+ >>> upload_request(b"""STORE 14 %s
... Content-Type: text/plain
... File-Content-ID: 123
... File-Alias-ID: 456
@@ -117,6 +117,4 @@ Unicode filenames work, but must be encoded as UTF-8 on the socket.
...
... Cats and dogs.""" % filename)
reply: '200'
- file u'Yow\u203d' stored as text/plain, contents: 'Cats and dogs.'
-
-
+ file 'Yow‽' stored as text/plain, contents: 'Cats and dogs.'
diff --git a/lib/lp/services/librarianserver/librariangc.py b/lib/lp/services/librarianserver/librariangc.py
index 3072629..af866ff 100644
--- a/lib/lp/services/librarianserver/librariangc.py
+++ b/lib/lp/services/librarianserver/librariangc.py
@@ -3,6 +3,8 @@
"""Librarian garbage collection routines"""
+from __future__ import absolute_import, print_function, unicode_literals
+
__metaclass__ = type
from datetime import (
diff --git a/lib/lp/services/librarianserver/libraryprotocol.py b/lib/lp/services/librarianserver/libraryprotocol.py
index 385d15e..6a8d61d 100644
--- a/lib/lp/services/librarianserver/libraryprotocol.py
+++ b/lib/lp/services/librarianserver/libraryprotocol.py
@@ -1,6 +1,8 @@
# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
+from __future__ import absolute_import, print_function, unicode_literals
+
__metaclass__ = type
from datetime import datetime
@@ -67,6 +69,10 @@ class FileUploadProtocol(basic.LineReceiver):
def lineReceived(self, line):
try:
+ try:
+ line = line.decode('UTF-8')
+ except UnicodeDecodeError:
+ raise ProtocolViolation('Non-data lines must be in UTF-8')
getattr(self, 'line_' + self.state, self.badLine)(line)
except ProtocolViolation as e:
self.sendError(e.msg)
@@ -156,11 +162,6 @@ class FileUploadProtocol(basic.LineReceiver):
def command_STORE(self, args):
try:
size, name = args.split(None, 1)
- try:
- name = name.decode('utf-8')
- except:
- raise ProtocolViolation(
- "STORE command expects the filename to be in UTF-8")
size = int(size)
except ValueError:
raise ProtocolViolation(
diff --git a/lib/lp/services/librarianserver/storage.py b/lib/lp/services/librarianserver/storage.py
index 253bc41..89af9d6 100644
--- a/lib/lp/services/librarianserver/storage.py
+++ b/lib/lp/services/librarianserver/storage.py
@@ -1,6 +1,8 @@
# Copyright 2009-2019 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
+from __future__ import absolute_import, print_function, unicode_literals
+
__metaclass__ = type
import errno
diff --git a/lib/lp/services/librarianserver/swift.py b/lib/lp/services/librarianserver/swift.py
index 4407ffd..b45293f 100644
--- a/lib/lp/services/librarianserver/swift.py
+++ b/lib/lp/services/librarianserver/swift.py
@@ -3,6 +3,8 @@
"""Move files from Librarian disk storage into Swift."""
+from __future__ import absolute_import, print_function, unicode_literals
+
__metaclass__ = type
__all__ = [
'SWIFT_CONTAINER_PREFIX',
diff --git a/lib/lp/services/librarianserver/testing/fake.py b/lib/lp/services/librarianserver/testing/fake.py
index c482abe..46ca6f1 100644
--- a/lib/lp/services/librarianserver/testing/fake.py
+++ b/lib/lp/services/librarianserver/testing/fake.py
@@ -10,6 +10,8 @@ provides a simple and fast alternative to the full Librarian in unit
tests.
"""
+from __future__ import absolute_import, print_function, unicode_literals
+
__metaclass__ = type
__all__ = [
'FakeLibrarian',
diff --git a/lib/lp/services/librarianserver/testing/server.py b/lib/lp/services/librarianserver/testing/server.py
index ee11175..0ac1a68 100644
--- a/lib/lp/services/librarianserver/testing/server.py
+++ b/lib/lp/services/librarianserver/testing/server.py
@@ -3,6 +3,8 @@
"""Fixture for the librarians."""
+from __future__ import absolute_import, print_function, unicode_literals
+
__metaclass__ = type
__all__ = [
'fillLibrarianFile',
diff --git a/lib/lp/services/librarianserver/testing/tests/test_fakelibrarian.py b/lib/lp/services/librarianserver/testing/tests/test_fakelibrarian.py
index ac849c5..d4cc436 100644
--- a/lib/lp/services/librarianserver/testing/tests/test_fakelibrarian.py
+++ b/lib/lp/services/librarianserver/testing/tests/test_fakelibrarian.py
@@ -3,6 +3,8 @@
"""Test the fake librarian."""
+from __future__ import absolute_import, print_function, unicode_literals
+
__metaclass__ = type
import io
diff --git a/lib/lp/services/librarianserver/tests/test_apachelogparser.py b/lib/lp/services/librarianserver/tests/test_apachelogparser.py
index 1be4c14..c81cd3f 100644
--- a/lib/lp/services/librarianserver/tests/test_apachelogparser.py
+++ b/lib/lp/services/librarianserver/tests/test_apachelogparser.py
@@ -1,6 +1,8 @@
# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
+from __future__ import absolute_import, print_function, unicode_literals
+
from datetime import datetime
import io
import os
@@ -35,52 +37,52 @@ class TestRequestParsing(TestCase):
def assertMethodAndFileIDAreCorrect(self, request):
method, path = get_method_and_path(request)
file_id = get_library_file_id(path)
- self.assertEqual(method, 'GET')
+ self.assertEqual(method, b'GET')
self.assertEqual(file_id, '8196569')
def test_return_value(self):
- request = 'GET /8196569/mediumubuntulogo.png HTTP/1.1'
+ request = b'GET /8196569/mediumubuntulogo.png HTTP/1.1'
self.assertMethodAndFileIDAreCorrect(request)
def test_return_value_for_http_path(self):
- request = ('GET http://launchpadlibrarian.net/8196569/'
- 'mediumubuntulogo.png HTTP/1.1')
+ request = (b'GET http://launchpadlibrarian.net/8196569/'
+ b'mediumubuntulogo.png HTTP/1.1')
self.assertMethodAndFileIDAreCorrect(request)
def test_extra_slashes_are_ignored(self):
- request = 'GET http://launchpadlibrarian.net//8196569//foo HTTP/1.1'
+ request = b'GET http://launchpadlibrarian.net//8196569//foo HTTP/1.1'
self.assertMethodAndFileIDAreCorrect(request)
- request = 'GET //8196569//foo HTTP/1.1'
+ request = b'GET //8196569//foo HTTP/1.1'
self.assertMethodAndFileIDAreCorrect(request)
def test_multiple_consecutive_white_spaces(self):
# Some request strings might have multiple consecutive white spaces,
# but they're parsed just like if they didn't have the extra spaces.
- request = 'GET /8196569/mediumubuntulogo.png HTTP/1.1'
+ request = b'GET /8196569/mediumubuntulogo.png HTTP/1.1'
self.assertMethodAndFileIDAreCorrect(request)
def test_return_value_for_https_path(self):
- request = ('GET https://launchpadlibrarian.net/8196569/'
- 'mediumubuntulogo.png HTTP/1.1')
+ request = (b'GET https://launchpadlibrarian.net/8196569/'
+ b'mediumubuntulogo.png HTTP/1.1')
self.assertMethodAndFileIDAreCorrect(request)
def test_return_value_for_request_missing_http_version(self):
# HTTP 1.0 requests might omit the HTTP version so we must cope with
# them.
- request = 'GET https://launchpadlibrarian.net/8196569/foo.png'
+ request = b'GET https://launchpadlibrarian.net/8196569/foo.png'
self.assertMethodAndFileIDAreCorrect(request)
def test_requests_for_paths_that_are_not_of_an_lfa_return_none(self):
- request = 'GET https://launchpadlibrarian.net/ HTTP/1.1'
+ request = b'GET https://launchpadlibrarian.net/ HTTP/1.1'
self.assertEqual(
get_library_file_id(get_method_and_path(request)[1]), None)
- request = 'GET /robots.txt HTTP/1.1'
+ request = b'GET /robots.txt HTTP/1.1'
self.assertEqual(
get_library_file_id(get_method_and_path(request)[1]), None)
- request = 'GET /@@person HTTP/1.1'
+ request = b'GET /@@person HTTP/1.1'
self.assertEqual(
get_library_file_id(get_method_and_path(request)[1]), None)
diff --git a/lib/lp/services/librarianserver/tests/test_db.py b/lib/lp/services/librarianserver/tests/test_db.py
index 3dd2a5b..be7327e 100644
--- a/lib/lp/services/librarianserver/tests/test_db.py
+++ b/lib/lp/services/librarianserver/tests/test_db.py
@@ -1,6 +1,8 @@
# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
+from __future__ import absolute_import, print_function, unicode_literals
+
__metaclass__ = type
from fixtures import MockPatchObject
@@ -208,8 +210,8 @@ class TestLibrarianStuff(TestCase):
library = db.Library(restricted=False)
aliases = library.getAliases(1)
expected_aliases = [
- (1, u'netapplet-1.0.0.tar.gz', u'application/x-gtar'),
- (2, u'netapplet_1.0.0.orig.tar.gz', u'application/x-gtar'),
+ (1, 'netapplet-1.0.0.tar.gz', 'application/x-gtar'),
+ (2, 'netapplet_1.0.0.orig.tar.gz', 'application/x-gtar'),
]
self.assertEqual(expected_aliases, aliases)
@@ -221,7 +223,7 @@ class TestLibrarianStuff(TestCase):
alias.content = None
aliases = library.getAliases(1)
expected_aliases = [
- (2, u'netapplet_1.0.0.orig.tar.gz', u'application/x-gtar'),
+ (2, 'netapplet_1.0.0.orig.tar.gz', 'application/x-gtar'),
]
self.assertEqual(expected_aliases, aliases)
@@ -235,13 +237,13 @@ class TestLibrarianStuff(TestCase):
aliases = unrestricted_library.getAliases(1)
expected_aliases = [
- (2, u'netapplet_1.0.0.orig.tar.gz', u'application/x-gtar'),
+ (2, 'netapplet_1.0.0.orig.tar.gz', 'application/x-gtar'),
]
self.assertEqual(expected_aliases, aliases)
restricted_library = db.Library(restricted=True)
aliases = restricted_library.getAliases(1)
expected_aliases = [
- (1, u'netapplet-1.0.0.tar.gz', u'application/x-gtar'),
+ (1, 'netapplet-1.0.0.tar.gz', 'application/x-gtar'),
]
self.assertEqual(expected_aliases, aliases)
diff --git a/lib/lp/services/librarianserver/tests/test_db_outage.py b/lib/lp/services/librarianserver/tests/test_db_outage.py
index d6fa401..8642ace 100644
--- a/lib/lp/services/librarianserver/tests/test_db_outage.py
+++ b/lib/lp/services/librarianserver/tests/test_db_outage.py
@@ -5,6 +5,8 @@
Database outages happen by accident and during fastdowntime deployments."""
+from __future__ import absolute_import, print_function, unicode_literals
+
__metaclass__ = type
import io
diff --git a/lib/lp/services/librarianserver/tests/test_doc.py b/lib/lp/services/librarianserver/tests/test_doc.py
index ff7ea00..6a9ed9c 100644
--- a/lib/lp/services/librarianserver/tests/test_doc.py
+++ b/lib/lp/services/librarianserver/tests/test_doc.py
@@ -5,7 +5,7 @@
Run the doctests and pagetests.
"""
-from __future__ import absolute_import, print_function
+from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
@@ -25,7 +25,7 @@ from lp.testing.systemdocs import (
class MockTransport:
disconnecting = False
- bytesWritten = ''
+ bytesWritten = b''
connectionLost = False
def write(self, bytes):
@@ -45,7 +45,7 @@ class MockLibrary:
class MockFile:
- bytes = ''
+ bytes = b''
stored = False
databaseName = None
debugID = None
@@ -74,7 +74,7 @@ def upload_request(request):
closed, e.g.::
reply: '200'
- file u'foo.txt' stored as text/plain, contents: 'Foo!'
+ file 'foo.txt' stored as text/plain, contents: 'Foo!'
or::
@@ -115,18 +115,18 @@ def upload_request(request):
server.fileLibrary = MockLibrary()
# Feed in the request
- server.dataReceived(request.replace('\n', '\r\n'))
+ server.dataReceived(request.replace(b'\n', b'\r\n'))
# Report on what happened
- print("reply: %r" % server.transport.bytesWritten.rstrip('\r\n'))
+ print("reply: %r" % server.transport.bytesWritten.rstrip(b'\r\n'))
if server.transport.connectionLost:
print('connection closed')
mockFile = server.fileLibrary.file
if mockFile is not None and mockFile.stored:
- print("file %r stored as %s, contents: %r" %
- (mockFile.name, mockFile.mimetype, mockFile.bytes))
+ print("file '%s' stored as %s, contents: %r" % (
+ mockFile.name, mockFile.mimetype, mockFile.bytes))
# Cleanup: remove the observer.
log.removeObserver(log_observer)
@@ -137,12 +137,12 @@ here = os.path.dirname(os.path.realpath(__file__))
special = {
'librarian-report.txt': LayeredDocFileSuite(
'../doc/librarian-report.txt',
- setUp=setUp, tearDown=tearDown,
+ setUp=lambda test: setUp(test, future=True), tearDown=tearDown,
layer=LaunchpadZopelessLayer
),
'upload.txt': LayeredDocFileSuite(
'../doc/upload.txt',
- setUp=setUp, tearDown=tearDown,
+ setUp=lambda test: setUp(test, future=True), tearDown=tearDown,
layer=LaunchpadZopelessLayer,
globs={'upload_request': upload_request},
),
diff --git a/lib/lp/services/librarianserver/tests/test_gc.py b/lib/lp/services/librarianserver/tests/test_gc.py
index 71fb0c4..0c2465d 100644
--- a/lib/lp/services/librarianserver/tests/test_gc.py
+++ b/lib/lp/services/librarianserver/tests/test_gc.py
@@ -3,6 +3,8 @@
"""Librarian garbage collection tests"""
+from __future__ import absolute_import, print_function, unicode_literals
+
__metaclass__ = type
import calendar
diff --git a/lib/lp/services/librarianserver/tests/test_sigdumpmem.py b/lib/lp/services/librarianserver/tests/test_sigdumpmem.py
index 65801be..8bb7443 100644
--- a/lib/lp/services/librarianserver/tests/test_sigdumpmem.py
+++ b/lib/lp/services/librarianserver/tests/test_sigdumpmem.py
@@ -3,6 +3,8 @@
"""Test the SIGDUMPMEM signal handler."""
+from __future__ import absolute_import, print_function, unicode_literals
+
__metaclass__ = type
import os
diff --git a/lib/lp/services/librarianserver/tests/test_storage.py b/lib/lp/services/librarianserver/tests/test_storage.py
index c71a056..59b7cda 100644
--- a/lib/lp/services/librarianserver/tests/test_storage.py
+++ b/lib/lp/services/librarianserver/tests/test_storage.py
@@ -1,6 +1,8 @@
# Copyright 2009-2019 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
+from __future__ import absolute_import, print_function, unicode_literals
+
import hashlib
import shutil
import tempfile
diff --git a/lib/lp/services/librarianserver/tests/test_swift.py b/lib/lp/services/librarianserver/tests/test_swift.py
index 6fe7ffd..98ebc86 100644
--- a/lib/lp/services/librarianserver/tests/test_swift.py
+++ b/lib/lp/services/librarianserver/tests/test_swift.py
@@ -3,6 +3,8 @@
"""Librarian disk to Swift storage tests."""
+from __future__ import absolute_import, print_function, unicode_literals
+
__metaclass__ = type
import hashlib
diff --git a/lib/lp/services/librarianserver/tests/test_web.py b/lib/lp/services/librarianserver/tests/test_web.py
index c7ceeeb..5133aa5 100644
--- a/lib/lp/services/librarianserver/tests/test_web.py
+++ b/lib/lp/services/librarianserver/tests/test_web.py
@@ -1,6 +1,8 @@
# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
+from __future__ import absolute_import, print_function, unicode_literals
+
__metaclass__ = type
from datetime import datetime
@@ -159,7 +161,7 @@ class LibrarianWebTestCase(LibrarianWebTestMixin, TestCaseWithFactory):
# displaying Ubuntu build logs in the browser. The mimetype should be
# "text/plain" for these files.
client = LibrarianClient()
- contents = u'Build log \N{SNOWMAN}...'.encode('UTF-8')
+ contents = 'Build log \N{SNOWMAN}...'.encode('UTF-8')
build_log = BytesIO()
with GzipFile(mode='wb', fileobj=build_log) as f:
f.write(contents)
diff --git a/lib/lp/services/librarianserver/web.py b/lib/lp/services/librarianserver/web.py
index bb0612a..0d6278b 100644
--- a/lib/lp/services/librarianserver/web.py
+++ b/lib/lp/services/librarianserver/web.py
@@ -1,6 +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 __future__ import absolute_import, print_function, unicode_literals
+
__metaclass__ = type
from datetime import datetime
@@ -50,7 +52,7 @@ defaultResource = static.Data(b"""
<p><small>Copyright 2004-2020 Canonical Ltd.</small></p>
<!-- kthxbye. -->
</body></html>
- """, type='text/html')
+ """, type=six.ensure_str('text/html'))
fourOhFour = resource.NoResource('No such resource')
@@ -316,7 +318,8 @@ class DigestSearchResource(resource.Resource):
try:
digest = request.args['digest'][0]
except LookupError:
- return static.Data(b'Bad search', 'text/plain').render(request)
+ return static.Data(
+ b'Bad search', six.ensure_str('text/plain')).render(request)
deferred = deferToThread(self._matchingAliases, digest)
deferred.addCallback(self._cb_matchingAliases, request)
@@ -333,8 +336,9 @@ class DigestSearchResource(resource.Resource):
def _cb_matchingAliases(self, matches, request):
text = '\n'.join([str(len(matches))] + matches)
- response = static.Data(text.encode('utf-8'),
- 'text/plain; charset=utf-8').render(request)
+ response = static.Data(
+ text.encode('utf-8'),
+ six.ensure_str('text/plain; charset=utf-8')).render(request)
request.write(response)
request.finish()
@@ -343,7 +347,7 @@ class DigestSearchResource(resource.Resource):
robotsTxt = static.Data(b"""
User-agent: *
Disallow: /
-""", type='text/plain')
+""", type=six.ensure_str('text/plain'))
def _eb(failure, request):