From 7d70b6b3a3bde089bfca3960a51a524532b140cd Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Mon, 15 Dec 2014 03:25:41 +0000 Subject: [PATCH 01/35] Dropping mox --- ubuntutools/test/test_archive.py | 16 +++++++--------- ubuntutools/test/test_config.py | 14 ++++++++++---- ubuntutools/test/test_update_maintainer.py | 16 +++++++++++----- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/ubuntutools/test/test_archive.py b/ubuntutools/test/test_archive.py index 69ccd9c..3be3383 100644 --- a/ubuntutools/test/test_archive.py +++ b/ubuntutools/test/test_archive.py @@ -20,12 +20,14 @@ import __builtin__ import os.path import shutil import StringIO +from io import BytesIO import tempfile import types import urllib2 import debian.deb822 import httplib2 +import mock import mox import ubuntutools.archive @@ -44,15 +46,11 @@ def setUpModule(): ex_pkg.cleanup() -class DscVerificationTestCase(mox.MoxTestBase, unittest.TestCase): +class DscVerificationTestCase(unittest.TestCase): def setUp(self): - super(DscVerificationTestCase, self).setUp() with open('test-data/example_1.0-1.dsc', 'rb') as f: self.dsc = ubuntutools.archive.Dsc(f.read()) - def tearDown(self): - super(DscVerificationTestCase, self).tearDown() - def test_good(self): self.assertTrue(self.dsc.verify_file( 'test-data/example_1.0.orig.tar.gz')) @@ -68,10 +66,10 @@ class DscVerificationTestCase(mox.MoxTestBase, unittest.TestCase): with open(fn, 'rb') as f: data = f.read() data = data[:-1] + chr(ord(data[-1]) ^ 8) - self.mox.StubOutWithMock(__builtin__, 'open') - open(fn, 'rb').AndReturn(StringIO.StringIO(data)) - self.mox.ReplayAll() - self.assertFalse(self.dsc.verify_file(fn)) + m = mock.MagicMock(name='open', spec=open) + m.return_value = BytesIO(data) + with mock.patch('__builtin__.open', m): + self.assertFalse(self.dsc.verify_file(fn)) def test_sha1(self): del self.dsc['Checksums-Sha256'] diff --git a/ubuntutools/test/test_config.py b/ubuntutools/test/test_config.py index e32d5dc..68d5fa7 100644 --- a/ubuntutools/test/test_config.py +++ b/ubuntutools/test/test_config.py @@ -19,15 +19,16 @@ import __builtin__ import os import sys import locale +from io import BytesIO from StringIO import StringIO -import mox +import mock from ubuntutools.config import UDTConfig, ubu_email from ubuntutools.logger import Logger from ubuntutools.test import unittest -class ConfigTestCase(mox.MoxTestBase, unittest.TestCase): +class ConfigTestCase(unittest.TestCase): _config_files = { 'system': '', 'user': '', @@ -42,11 +43,16 @@ class ConfigTestCase(mox.MoxTestBase, unittest.TestCase): } if filename not in files: raise IOError("No such file or directory: '%s'" % filename) - return StringIO(files[filename]) + return BytesIO(files[filename]) def setUp(self): super(ConfigTestCase, self).setUp() - self.mox.stubs.Set(__builtin__, 'open', self._fake_open) + m = mock.mock_open() + m.side_effect = self._fake_open + patcher = mock.patch('__builtin__.open', m) + self.addCleanup(patcher.stop) + self.MockOpen = self.patcher.start() + Logger.stdout = StringIO() Logger.stderr = StringIO() diff --git a/ubuntutools/test/test_update_maintainer.py b/ubuntutools/test/test_update_maintainer.py index d08bd73..808e609 100644 --- a/ubuntutools/test/test_update_maintainer.py +++ b/ubuntutools/test/test_update_maintainer.py @@ -21,7 +21,7 @@ import os import StringIO import sys -import mox +import mock from ubuntutools.logger import Logger from ubuntutools.test import unittest @@ -186,7 +186,7 @@ Package: seahorse-plugins """ #pylint: disable=R0904 -class UpdateMaintainerTestCase(mox.MoxTestBase, unittest.TestCase): +class UpdateMaintainerTestCase(unittest.TestCase): """TestCase object for ubuntutools.update_maintainer""" _directory = "/" @@ -216,9 +216,15 @@ class UpdateMaintainerTestCase(mox.MoxTestBase, unittest.TestCase): #pylint: disable=C0103 def setUp(self): - super(UpdateMaintainerTestCase, self).setUp() - self.mox.stubs.Set(__builtin__, 'open', self._fake_open) - self.mox.stubs.Set(os.path, 'isfile', self._fake_isfile) + m = mock.mock_open() + m.side_effect = self._fake_open + patcher = mock.patch('__builtin__.open', m) + self.addCleanup(patcher.stop) + self.MockOpen = patcher.start() + m = mock.MagicMock(side_effect=self._fake_isfile) + patcher = mock.patch('os.path.isfile', m) + self.addCleanup(patcher.stop) + self.MockIsfile = patcher.start() self._files["rules"] = StringIO.StringIO(_SIMPLE_RULES) Logger.stdout = StringIO.StringIO() Logger.stderr = StringIO.StringIO() From 72487d047790492e6dcca728f50c9832bee596a2 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Mon, 15 Dec 2014 03:42:49 +0000 Subject: [PATCH 02/35] Stubout --- ubuntutools/test/test_archive.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ubuntutools/test/test_archive.py b/ubuntutools/test/test_archive.py index 3be3383..48b2311 100644 --- a/ubuntutools/test/test_archive.py +++ b/ubuntutools/test/test_archive.py @@ -90,16 +90,21 @@ class LocalSourcePackageTestCase(mox.MoxTestBase, unittest.TestCase): super(LocalSourcePackageTestCase, self).setUp() self.workdir = tempfile.mkdtemp(prefix='udt-test') - self.mox.StubOutWithMock(ubuntutools.archive, 'Distribution') - self.mox.StubOutWithMock(ubuntutools.archive, 'rmadison') + self._stubout('ubuntutools.archive.Distribution') + self._stubout('ubuntutools.archive.rmadison') self.real_http = httplib2.Http() self.mox.StubOutWithMock(httplib2, 'Http') self.mock_http = self.mox.CreateMock(httplib2.Http) # Silence the tests a little: - self.mox.stubs.Set(Logger, 'stdout', StringIO.StringIO()) - self.mox.stubs.Set(Logger, 'stderr', StringIO.StringIO()) + self._stubout('ubuntutools.logger.Logger.stdout') + self._stubout('ubuntutools.logger.Logger.stderr') + + def _stubout(self, stub): + patcher = mock.patch(stub) + self.addCleanup(patcher.stop) + patcher.start() def tearDown(self): super(LocalSourcePackageTestCase, self).tearDown() From 522030be122ed43c6c018eca4a15b0caf86ba004 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Mon, 15 Dec 2014 03:47:59 +0000 Subject: [PATCH 03/35] don't keep unused mocks --- ubuntutools/test/test_config.py | 2 +- ubuntutools/test/test_update_maintainer.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ubuntutools/test/test_config.py b/ubuntutools/test/test_config.py index 68d5fa7..a48902f 100644 --- a/ubuntutools/test/test_config.py +++ b/ubuntutools/test/test_config.py @@ -51,7 +51,7 @@ class ConfigTestCase(unittest.TestCase): m.side_effect = self._fake_open patcher = mock.patch('__builtin__.open', m) self.addCleanup(patcher.stop) - self.MockOpen = self.patcher.start() + patcher.start() Logger.stdout = StringIO() Logger.stderr = StringIO() diff --git a/ubuntutools/test/test_update_maintainer.py b/ubuntutools/test/test_update_maintainer.py index 808e609..40be54a 100644 --- a/ubuntutools/test/test_update_maintainer.py +++ b/ubuntutools/test/test_update_maintainer.py @@ -220,11 +220,11 @@ class UpdateMaintainerTestCase(unittest.TestCase): m.side_effect = self._fake_open patcher = mock.patch('__builtin__.open', m) self.addCleanup(patcher.stop) - self.MockOpen = patcher.start() + patcher.start() m = mock.MagicMock(side_effect=self._fake_isfile) patcher = mock.patch('os.path.isfile', m) self.addCleanup(patcher.stop) - self.MockIsfile = patcher.start() + patcher.start() self._files["rules"] = StringIO.StringIO(_SIMPLE_RULES) Logger.stdout = StringIO.StringIO() Logger.stderr = StringIO.StringIO() From 88e3d1d6ba14cb0f0e728f66a5ef88b024cf13a1 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Mon, 15 Dec 2014 04:24:41 +0000 Subject: [PATCH 04/35] Port http_mock to mock. --- ubuntutools/test/test_archive.py | 44 +++++++++----------------------- 1 file changed, 12 insertions(+), 32 deletions(-) diff --git a/ubuntutools/test/test_archive.py b/ubuntutools/test/test_archive.py index 48b2311..5ef40d6 100644 --- a/ubuntutools/test/test_archive.py +++ b/ubuntutools/test/test_archive.py @@ -93,9 +93,8 @@ class LocalSourcePackageTestCase(mox.MoxTestBase, unittest.TestCase): self._stubout('ubuntutools.archive.Distribution') self._stubout('ubuntutools.archive.rmadison') - self.real_http = httplib2.Http() - self.mox.StubOutWithMock(httplib2, 'Http') - self.mock_http = self.mox.CreateMock(httplib2.Http) + self.mock_http = self._stubout('httplib2.Http.request') + self.mock_http.side_effect = self.request_proxy # Silence the tests a little: self._stubout('ubuntutools.logger.Logger.stdout') @@ -104,7 +103,7 @@ class LocalSourcePackageTestCase(mox.MoxTestBase, unittest.TestCase): def _stubout(self, stub): patcher = mock.patch(stub) self.addCleanup(patcher.stop) - patcher.start() + return patcher.start() def tearDown(self): super(LocalSourcePackageTestCase, self).tearDown() @@ -144,6 +143,12 @@ class LocalSourcePackageTestCase(mox.MoxTestBase, unittest.TestCase): response = httplib2.Response({'status': 404}) return response, "I'm a 404 Error" + def request_404_then_proxy(self, url, destname=None): + "mock side_effect callable to chain request 404 & proxy" + if self.mock_http.called: + return self.request_proxy(url, destname) + return self.request_404(url) + def test_local_copy(self): pkg = self.SourcePackage('example', '1.0-1', 'main', dscfile='test-data/example_1.0-1.dsc', @@ -191,10 +196,6 @@ class LocalSourcePackageTestCase(mox.MoxTestBase, unittest.TestCase): dist = self.SourcePackage.distribution mirror = UDTConfig.defaults['%s_MIRROR' % dist.upper()] urlbase = '/pool/main/e/example/' - httplib2.Http().AndReturn(self.mock_http) - self.mock_http.request('https://launchpad.net/%s/+archive/primary/' - '+files/example_1.0-1.dsc' % dist - ).WithSideEffects(self.request_proxy) url_opener = self.mox.CreateMock(urllib2.OpenerDirector) url_opener.open(mirror + urlbase + 'example_1.0.orig.tar.gz' ).WithSideEffects(self.urlopen_proxy) @@ -212,9 +213,6 @@ class LocalSourcePackageTestCase(mox.MoxTestBase, unittest.TestCase): mirror = 'http://mirror' lpbase = 'https://launchpad.net/ubuntu/+archive/primary/+files/' urlbase = '/pool/main/e/example/' - httplib2.Http().AndReturn(self.mock_http) - self.mock_http.request(lpbase + 'example_1.0-1.dsc' - ).WithSideEffects(self.request_proxy) url_opener = self.mox.CreateMock(urllib2.OpenerDirector) url_opener.open(mirror + urlbase + 'example_1.0.orig.tar.gz' ).WithSideEffects(self.urlopen_null) @@ -232,12 +230,7 @@ class LocalSourcePackageTestCase(mox.MoxTestBase, unittest.TestCase): pkg.pull() def test_dsc_missing(self): - lpbase = 'https://launchpad.net/ubuntu/+archive/primary/+files/' - httplib2.Http().AndReturn(self.mock_http) - self.mock_http.request(lpbase + 'example_1.0-1.dsc' - ).WithSideEffects(self.request_404) - self.mox.ReplayAll() - + self.mock_http.side_effect = self.request_404 pkg = self.SourcePackage('example', '1.0-1', 'main', workdir=self.workdir) self.assertRaises(ubuntutools.archive.DownloadError, pkg.pull) @@ -254,9 +247,6 @@ class DebianLocalSourcePackageTestCase(LocalSourcePackageTestCase): lpbase = 'https://launchpad.net/debian/+archive/primary/+files/' base = '/pool/main/e/example/' - httplib2.Http().AndReturn(self.mock_http) - self.mock_http.request(lpbase + 'example_1.0-1.dsc' - ).WithSideEffects(self.request_proxy) url_opener = self.mox.CreateMock(urllib2.OpenerDirector) url_opener.open(debian_mirror + base + 'example_1.0.orig.tar.gz' ).WithSideEffects(self.urlopen_null) @@ -291,12 +281,7 @@ class DebianLocalSourcePackageTestCase(LocalSourcePackageTestCase): mirror = 'http://mirror' lpbase = 'https://launchpad.net/debian/+archive/primary/+files/' base = '/pool/main/e/example/' - httplib2.Http().AndReturn(self.mock_http) - self.mock_http.request(lpbase + 'example_1.0-1.dsc' - ).WithSideEffects(self.request_404) - httplib2.Http().AndReturn(self.mock_http) - self.mock_http.request(mirror + base + 'example_1.0-1.dsc' - ).WithSideEffects(self.request_proxy) + self.mock_http.side_effect = self.request_404_then_proxy url_opener = self.mox.CreateMock(urllib2.OpenerDirector) url_opener.open(mirror + base + 'example_1.0.orig.tar.gz' ).WithSideEffects(self.urlopen_proxy) @@ -326,12 +311,7 @@ class DebianLocalSourcePackageTestCase(LocalSourcePackageTestCase): mirror = 'http://mirror' lpbase = 'https://launchpad.net/debian/+archive/primary/+files/' base = '/pool/main/e/example/' - httplib2.Http().AndReturn(self.mock_http) - self.mock_http.request(lpbase + 'example_1.0-1.dsc' - ).WithSideEffects(self.request_404) - httplib2.Http().AndReturn(self.mock_http) - self.mock_http.request(mirror + base + 'example_1.0-1.dsc' - ).WithSideEffects(self.request_proxy) + self.mock_http.side_effect = self.request_404_then_proxy def fake_gpg_info(self, message, keyrings=None): return debian.deb822.GpgInfo.from_output( From d4f6ef320e80e29433227c2f4cdb3ce12b7881bb Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Tue, 16 Dec 2014 01:44:13 +0000 Subject: [PATCH 05/35] remains of mox --- debian/control | 1 - ubuntutools/test/test_archive.py | 113 +++++++++++-------------------- ubuntutools/test/test_pylint.py | 3 - 3 files changed, 38 insertions(+), 79 deletions(-) diff --git a/debian/control b/debian/control index 5263945..e5249b8 100644 --- a/debian/control +++ b/debian/control @@ -19,7 +19,6 @@ Build-Depends: dctrl-tools, python-distro-info (>= 0.4~), python-httplib2, python-launchpadlib (>= 1.5.7), - python-mox, python-setuptools, python-soappy, python-unittest2 diff --git a/ubuntutools/test/test_archive.py b/ubuntutools/test/test_archive.py index 5ef40d6..9c792f5 100644 --- a/ubuntutools/test/test_archive.py +++ b/ubuntutools/test/test_archive.py @@ -28,7 +28,6 @@ import urllib2 import debian.deb822 import httplib2 import mock -import mox import ubuntutools.archive from ubuntutools.config import UDTConfig @@ -83,11 +82,10 @@ class DscVerificationTestCase(unittest.TestCase): self.test_bad() -class LocalSourcePackageTestCase(mox.MoxTestBase, unittest.TestCase): +class LocalSourcePackageTestCase(unittest.TestCase): SourcePackage = ubuntutools.archive.UbuntuSourcePackage def setUp(self): - super(LocalSourcePackageTestCase, self).setUp() self.workdir = tempfile.mkdtemp(prefix='udt-test') self._stubout('ubuntutools.archive.Distribution') @@ -96,6 +94,9 @@ class LocalSourcePackageTestCase(mox.MoxTestBase, unittest.TestCase): self.mock_http = self._stubout('httplib2.Http.request') self.mock_http.side_effect = self.request_proxy + self.url_opener = mock.MagicMock(spec=urllib2.OpenerDirector) + self.url_opener.open.side_effect = self.urlopen_proxy + # Silence the tests a little: self._stubout('ubuntutools.logger.Logger.stdout') self._stubout('ubuntutools.logger.Logger.stderr') @@ -106,7 +107,6 @@ class LocalSourcePackageTestCase(mox.MoxTestBase, unittest.TestCase): return patcher.start() def tearDown(self): - super(LocalSourcePackageTestCase, self).tearDown() shutil.rmtree(self.workdir) def urlopen_proxy(self, url, destname=None): @@ -196,16 +196,11 @@ class LocalSourcePackageTestCase(mox.MoxTestBase, unittest.TestCase): dist = self.SourcePackage.distribution mirror = UDTConfig.defaults['%s_MIRROR' % dist.upper()] urlbase = '/pool/main/e/example/' - url_opener = self.mox.CreateMock(urllib2.OpenerDirector) - url_opener.open(mirror + urlbase + 'example_1.0.orig.tar.gz' - ).WithSideEffects(self.urlopen_proxy) - url_opener.open(mirror + urlbase + 'example_1.0-1.debian.tar.xz' - ).WithSideEffects(self.urlopen_proxy) - self.mox.ReplayAll() pkg = self.SourcePackage('example', '1.0-1', 'main', workdir=self.workdir) - pkg.url_opener = url_opener + + pkg.url_opener = self.url_opener pkg.pull() def test_mirrors(self): @@ -213,16 +208,12 @@ class LocalSourcePackageTestCase(mox.MoxTestBase, unittest.TestCase): mirror = 'http://mirror' lpbase = 'https://launchpad.net/ubuntu/+archive/primary/+files/' urlbase = '/pool/main/e/example/' - url_opener = self.mox.CreateMock(urllib2.OpenerDirector) - url_opener.open(mirror + urlbase + 'example_1.0.orig.tar.gz' - ).WithSideEffects(self.urlopen_null) - url_opener.open(master + urlbase + 'example_1.0.orig.tar.gz' - ).WithSideEffects(self.urlopen_404) - url_opener.open(lpbase + 'example_1.0.orig.tar.gz' - ).WithSideEffects(self.urlopen_proxy) - url_opener.open(mirror + urlbase + 'example_1.0-1.debian.tar.xz' - ).WithSideEffects(self.urlopen_proxy) - self.mox.ReplayAll() + sequence = [self.urlopen_null, self.urlopen_404, self.urlopen_proxy, + self.urlopen_proxy] + def _callable_iter(*args, **kwargs): + return sequence.pop(0)(*args, **kwargs) + url_opener = mock.MagicMock(spec=urllib2.OpenerDirector) + url_opener.open.side_effect = _callable_iter pkg = self.SourcePackage('example', '1.0-1', 'main', workdir=self.workdir, mirrors=[mirror]) @@ -247,28 +238,19 @@ class DebianLocalSourcePackageTestCase(LocalSourcePackageTestCase): lpbase = 'https://launchpad.net/debian/+archive/primary/+files/' base = '/pool/main/e/example/' - url_opener = self.mox.CreateMock(urllib2.OpenerDirector) - url_opener.open(debian_mirror + base + 'example_1.0.orig.tar.gz' - ).WithSideEffects(self.urlopen_null) - url_opener.open(debsec_mirror + base + 'example_1.0.orig.tar.gz' - ).WithSideEffects(self.urlopen_404) - url_opener.open(debian_master + base + 'example_1.0.orig.tar.gz' - ).WithSideEffects(self.urlopen_404) - url_opener.open(debsec_master + base + 'example_1.0.orig.tar.gz' - ).WithSideEffects(self.urlopen_404) - url_opener.open(lpbase + 'example_1.0.orig.tar.gz' - ).WithSideEffects(self.urlopen_404) - url_opener.open('http://snapshot.debian.org/mr/package/example/1.0-1/' - 'srcfiles?fileinfo=1' - ).WithSideEffects(lambda x: StringIO.StringIO( - '{"fileinfo": {"hashabc": [{"name": "example_1.0.orig.tar.gz"}]}}' - )) - url_opener.open('http://snapshot.debian.org/file/hashabc' - ).WithSideEffects(self.urlopen_file( - 'example_1.0.orig.tar.gz')) - url_opener.open(debian_mirror + base + 'example_1.0-1.debian.tar.xz' - ).WithSideEffects(self.urlopen_proxy) - self.mox.ReplayAll() + sequence = [self.urlopen_null, + self.urlopen_404, + self.urlopen_404, + self.urlopen_404, + self.urlopen_404, + lambda x: BytesIO( + '{"fileinfo": {"hashabc": [{"name": "example_1.0.orig.tar.gz"}]}}'), + self.urlopen_file('example_1.0.orig.tar.gz'), + self.urlopen_proxy] + def _callable_iter(*args, **kwargs): + return sequence.pop(0)(*args, **kwargs) + url_opener = mock.MagicMock(spec=urllib2.OpenerDirector) + url_opener.open.side_effect = _callable_iter pkg = self.SourcePackage('example', '1.0-1', 'main', workdir=self.workdir, mirrors=[debian_mirror, @@ -282,29 +264,17 @@ class DebianLocalSourcePackageTestCase(LocalSourcePackageTestCase): lpbase = 'https://launchpad.net/debian/+archive/primary/+files/' base = '/pool/main/e/example/' self.mock_http.side_effect = self.request_404_then_proxy - url_opener = self.mox.CreateMock(urllib2.OpenerDirector) - url_opener.open(mirror + base + 'example_1.0.orig.tar.gz' - ).WithSideEffects(self.urlopen_proxy) - url_opener.open(mirror + base + 'example_1.0-1.debian.tar.xz' - ).WithSideEffects(self.urlopen_proxy) - def fake_gpg_info(self, message, keyrings=None): - return debian.deb822.GpgInfo.from_output( - '[GNUPG:] GOODSIG DEADBEEF Joe Developer ' - '') - # We have to stub this out without mox because there some versions of - # python-debian will pass keyrings=None, others won't. - # http://code.google.com/p/pymox/issues/detail?id=37 - self.mox.stubs.Set(debian.deb822.GpgInfo, 'from_sequence', - types.MethodType(fake_gpg_info, - debian.deb822.GpgInfo, - debian.deb822.GpgInfo)) - - self.mox.ReplayAll() + patcher = mock.patch.object(debian.deb822.GpgInfo, 'from_sequence') + self.addCleanup(patcher.stop) + mock_gpg_info = patcher.start() + mock_gpg_info.return_value = debian.deb822.GpgInfo.from_output( + '[GNUPG:] GOODSIG DEADBEEF Joe Developer ' + '') pkg = self.SourcePackage('example', '1.0-1', 'main', workdir=self.workdir, mirrors=[mirror]) - pkg.url_opener = url_opener + pkg.url_opener = self.url_opener pkg.pull() def test_dsc_badsig(self): @@ -313,19 +283,12 @@ class DebianLocalSourcePackageTestCase(LocalSourcePackageTestCase): base = '/pool/main/e/example/' self.mock_http.side_effect = self.request_404_then_proxy - def fake_gpg_info(self, message, keyrings=None): - return debian.deb822.GpgInfo.from_output( - '[GNUPG:] ERRSIG DEADBEEF') - # We have to stub this out without mox because there some versions of - # python-debian will pass keyrings=None, others won't. - # http://code.google.com/p/pymox/issues/detail?id=37 - self.mox.stubs.Set(debian.deb822.GpgInfo, 'from_sequence', - types.MethodType(fake_gpg_info, - debian.deb822.GpgInfo, - debian.deb822.GpgInfo)) - - self.mox.ReplayAll() - + patcher = mock.patch.object(debian.deb822.GpgInfo, 'from_sequence') + self.addCleanup(patcher.stop) + mock_gpg_info = patcher.start() + mock_gpg_info.return_value = debian.deb822.GpgInfo.from_output( + '[GNUPG:] ERRSIG DEADBEEF') + pkg = self.SourcePackage('example', '1.0-1', 'main', workdir=self.workdir, mirrors=[mirror]) self.assertRaises(ubuntutools.archive.DownloadError, pkg.pull) diff --git a/ubuntutools/test/test_pylint.py b/ubuntutools/test/test_pylint.py index 87552e4..f0b5847 100644 --- a/ubuntutools/test/test_pylint.py +++ b/ubuntutools/test/test_pylint.py @@ -25,9 +25,6 @@ WHITELIST = [re.compile(': %s$' % x) for x in ( r"No name '\w+Error' in module 'launchpadlib\.errors'", # http://www.logilab.org/ticket/51250: r"Module 'hashlib' has no '(md5|sha(1|224|256|384|512))' member", - # mox: - r"Instance of '.+' has no '(WithSideEffects|MultipleTimes|AndReturn)' " - r"member", # pylint doesn't like *args/**kwargs r"Instance of 'Popen' has no '.*' member", )] From a7dedd929665063e824e5ba232768575321599c2 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Tue, 16 Dec 2014 02:38:52 +0000 Subject: [PATCH 06/35] archive.py --- ubuntutools/archive.py | 49 +++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/ubuntutools/archive.py b/ubuntutools/archive.py index 555e72b..641c016 100644 --- a/ubuntutools/archive.py +++ b/ubuntutools/archive.py @@ -27,14 +27,23 @@ Approach: 3. Verify checksums. """ -from __future__ import with_statement +from __future__ import with_statement, print_function import hashlib import os.path -import urllib2 -import urlparse +try: + from urllib.request import ProxyHandler, build_opener, urlopen + from urllib.parse import urlparse + from urllib.error import URLError, HTTPError +except ImportError: + from urllib2 import ProxyHandler, build_opener, urlopen + from urlparse import urlparse + from urllib2 import URLError, HTTPError import re import sys +if sys.version_info[0] >= 3: + basestring = str + unicode = str from debian.changelog import Changelog, Version import debian.deb822 @@ -102,7 +111,7 @@ class Dsc(debian.deb822.Dsc): their_checksums = \ dict((entry['name'], (int(entry['size']), entry[key])) for entry in other[field]) - for name, (size, checksum) in our_checksums.iteritems(): + for name, (size, checksum) in our_checksums.items(): if name not in their_checksums: # file only in one dsc continue @@ -154,8 +163,8 @@ class SourcePackage(object): self.version = debian.debian_support.Version(version) # uses default proxies from the environment - proxy = urllib2.ProxyHandler() - self.url_opener = urllib2.build_opener(proxy) + proxy = ProxyHandler() + self.url_opener = build_opener(proxy) @property def lp_spph(self): @@ -231,10 +240,10 @@ class SourcePackage(object): def pull_dsc(self): "Retrieve dscfile and parse" if self._dsc_source: - parsed = urlparse.urlparse(self._dsc_source) + parsed = urlparse(self._dsc_source) if parsed.scheme == '': self._dsc_source = 'file://' + os.path.abspath(self._dsc_source) - parsed = urlparse.urlparse(self._dsc_source) + parsed = urlparse(self._dsc_source) url = self._dsc_source else: url = self._lp_url(self.dsc_name) @@ -244,14 +253,14 @@ class SourcePackage(object): def _download_dsc(self, url): "Download specified dscfile and parse" - parsed = urlparse.urlparse(url) + parsed = urlparse(url) if parsed.scheme == 'file': with open(parsed.path, 'r') as f: body = f.read() else: try: response, body = httplib2.Http().request(url) - except httplib2.HttpLib2Error, e: + except httplib2.HttpLib2Error as e: raise DownloadError(e) if response.status != 200: raise DownloadError("%s: %s %s" % (url, response.status, @@ -312,7 +321,7 @@ class SourcePackage(object): if entry['name'] == filename] assert len(size) == 1 size = int(size[0]) - parsed = urlparse.urlparse(url) + parsed = urlparse(url) if not self.quiet: Logger.normal('Downloading %s from %s (%0.3f MiB)', filename, parsed.hostname, size / 1024.0 / 1024) @@ -322,7 +331,7 @@ class SourcePackage(object): else: try: in_ = self.url_opener.open(url) - except urllib2.URLError: + except URLError: return False downloaded = 0 @@ -360,9 +369,9 @@ class SourcePackage(object): try: if self._download_file(url, name): break - except urllib2.HTTPError, e: + except HTTPError as e: Logger.normal('HTTP Error %i: %s', e.code, str(e)) - except urllib2.URLError, e: + except URLError as e: Logger.normal('URL Error: %s', e.reason) else: raise DownloadError('File %s could not be found' % name) @@ -457,7 +466,7 @@ class DebianSourcePackage(SourcePackage): wrapped_iterator = super(DebianSourcePackage, self)._source_urls(name) while True: try: - yield wrapped_iterator.next() + yield next(wrapped_iterator) except StopIteration: break if self.snapshot_list: @@ -503,7 +512,7 @@ class DebianSourcePackage(SourcePackage): 'http://snapshot.debian.org' '/mr/package/%s/%s/srcfiles?fileinfo=1' % (self.source, self.version.full_version))) - except urllib2.HTTPError: + except HTTPError: Logger.error('Version %s of %s not found on ' 'snapshot.debian.org', self.version.full_version, self.source) @@ -511,7 +520,7 @@ class DebianSourcePackage(SourcePackage): return False self._snapshot_list = dict((info[0]['name'], hash_) for hash_, info - in srcfiles['fileinfo'].iteritems()) + in srcfiles['fileinfo'].items()) return self._snapshot_list def _snapshot_url(self, name): @@ -569,9 +578,9 @@ class FakeSPPH(object): self.name + '_' + pkgversion, 'changelog' + extension) try: - self._changelog = urllib2.urlopen(url).read() - except urllib2.HTTPError, error: - print >> sys.stderr, ('%s: %s' % (url, error)) + self._changelog = urlopen(url).read() + except HTTPError as error: + print(('%s: %s' % (url, error)), file=sys.stderr) return None if since_version is None: From 65ab539516467d6c9b7c7da61c2e9d2a5ee25992 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Tue, 16 Dec 2014 02:48:52 +0000 Subject: [PATCH 07/35] harvest.py --- ubuntutools/harvest.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/ubuntutools/harvest.py b/ubuntutools/harvest.py index 8e222e1..21f6722 100644 --- a/ubuntutools/harvest.py +++ b/ubuntutools/harvest.py @@ -14,7 +14,12 @@ import json import os.path import sys -import urllib2 +try: + from urllib.request import urlopen + from urllib.error import URLError +except ImportError: + from urllib2 import urlopen + from urllib2 import URLError from ubuntutools.logger import Logger @@ -32,11 +37,11 @@ class Harvest(object): def _get_data(self): try: - sock = urllib2.urlopen(self.data_url) + sock = urlopen(self.data_url) except IOError: try: - urllib2.urlopen(BASE_URL) - except urllib2.URLError: + urlopen(BASE_URL) + except URLError: Logger.error("Harvest is down.") sys.exit(1) return None @@ -45,9 +50,7 @@ class Harvest(object): return json.loads(response) def opportunity_summary(self): - l = [] - for key in filter(lambda a: a != "total", self.data.keys()): - l += ["%s (%s)" % (key, self.data[key])] + l = ["%s (%s)" % (k,v) for (k,v) in self.data.items() if k != "total"] return ", ".join(l) def report(self): From 0c211c1bc74bd1dfaba4a1a94bf5117b5f50fbb5 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Tue, 16 Dec 2014 02:54:30 +0000 Subject: [PATCH 08/35] lp/libsupport.py --- ubuntutools/lp/libsupport.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/ubuntutools/lp/libsupport.py b/ubuntutools/lp/libsupport.py index 6155ea4..a2cb367 100644 --- a/ubuntutools/lp/libsupport.py +++ b/ubuntutools/lp/libsupport.py @@ -19,8 +19,11 @@ # # Modules. -import urllib -import urlparse +try: + from urllib.parse import urlsplit, urlencode, urlunsplit +except ImportError: + from urllib import urlencode + from urlparse import urlsplit, urlunsplit def query_to_dict(query_string): result = dict() @@ -31,7 +34,7 @@ def query_to_dict(query_string): return result def translate_web_api(url, launchpad): - scheme, netloc, path, query, fragment = urlparse.urlsplit(url) + scheme, netloc, path, query, fragment = urlsplit(url) query = query_to_dict(query) differences = set(netloc.split('.')).symmetric_difference( @@ -44,8 +47,8 @@ def translate_web_api(url, launchpad): if "ws.op" in query: raise ValueError("Invalid web url, url: %s" %url) query["ws.op"] = "searchTasks" - scheme, netloc, api_path, _, _ = urlparse.urlsplit(str(launchpad._root_uri)) - query = urllib.urlencode(query) - url = urlparse.urlunsplit((scheme, netloc, api_path + path.lstrip("/"), + scheme, netloc, api_path, _, _ = urlsplit(str(launchpad._root_uri)) + query = urlencode(query) + url = urlunsplit((scheme, netloc, api_path + path.lstrip("/"), query, fragment)) return url From 1bbedd4ddd8c349e54cf04cf290846f117cc6666 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 20:28:48 +0000 Subject: [PATCH 09/35] lpapicache --- ubuntutools/lp/lpapicache.py | 51 ++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/ubuntutools/lp/lpapicache.py b/ubuntutools/lp/lpapicache.py index 39bdc56..15b63bc 100644 --- a/ubuntutools/lp/lpapicache.py +++ b/ubuntutools/lp/lpapicache.py @@ -21,12 +21,34 @@ # # Based on code written by Jonathan Davies +from __future__ import print_function + # Uncomment for tracing LP API calls #import httplib2 #httplib2.debuglevel = 1 import sys +if sys.version_info[0] >= 3: + basestring = str + unicode = str + +#Shameless steal from python-six +def add_metaclass(metaclass): + """Class decorator for creating a class with a metaclass.""" + def wrapper(cls): + orig_vars = cls.__dict__.copy() + slots = orig_vars.get('__slots__') + if slots is not None: + if isinstance(slots, str): + slots = [slots] + for slots_var in slots: + orig_vars.pop(slots_var) + orig_vars.pop('__dict__', None) + orig_vars.pop('__weakref__', None) + return metaclass(cls.__name__, cls.__bases__, orig_vars) + return wrapper + from debian.changelog import Changelog, Version from httplib2 import Http, HttpLib2Error from launchpadlib.launchpad import Launchpad as LP @@ -39,6 +61,7 @@ from ubuntutools.lp.udtexceptions import (AlreadyLoggedInError, PackageNotFoundException, PocketDoesNotExistError, SeriesNotFoundException) +import collections __all__ = [ 'Archive', @@ -64,8 +87,8 @@ class _Launchpad(object): try: self.__lp = LP.login_with('ubuntu-dev-tools', service, version=api_version) - except IOError, error: - print >> sys.stderr, 'E: %s' % error + except IOError as error: + print('E: %s' % error, file=sys.stderr) raise else: raise AlreadyLoggedInError('Already logged in to Launchpad.') @@ -112,11 +135,11 @@ class MetaWrapper(type): cls._cache = dict() +@add_metaclass(MetaWrapper) class BaseWrapper(object): ''' A base class from which other wrapper classes are derived. ''' - __metaclass__ = MetaWrapper resource_type = None # it's a base class after all def __new__(cls, data): @@ -149,7 +172,7 @@ class BaseWrapper(object): cls._cache[data.self_link] = cached # add additional class specific caching (if available) cache = getattr(cls, 'cache', None) - if callable(cache): + if isinstance(cache, collections.Callable): cache(cached) return cached else: @@ -158,7 +181,7 @@ class BaseWrapper(object): else: # not a LP API representation, let the specific class handle it fetch = getattr(cls, 'fetch', None) - if callable(fetch): + if isinstance(fetch, collections.Callable): return fetch(data) else: raise NotImplementedError("Don't know how to fetch '%s' from LP" @@ -502,19 +525,19 @@ class SourcePackagePublishingHistory(BaseWrapper): if self._changelog is None: url = self._lpobject.changelogUrl() if url is None: - print >> sys.stderr, ('E: No changelog available for %s %s', + print(('E: No changelog available for %s %s', (self.getPackageName(), - self.getVersion())) + self.getVersion())), file=sys.stderr) return None try: response, changelog = Http().request(url) - except HttpLib2Error, e: - print >> sys.stderr, str(e) + except HttpLib2Error as e: + print(str(e), file=sys.stderr) return None if response.status != 200: - print >> sys.stderr, ('%s: %s %s' % (url, response.status, - response.reason)) + print(('%s: %s %s' % (url, response.status, + response.reason)), file=sys.stderr) return None self._changelog = changelog @@ -627,7 +650,7 @@ class MetaPersonTeam(MetaWrapper): if '_me' not in cls.__dict__: try: cls._me = PersonTeam(Launchpad.me) - except HTTPError, error: + except HTTPError as error: if error.response.status == 401: # Anonymous login cls._me = None @@ -636,11 +659,11 @@ class MetaPersonTeam(MetaWrapper): return cls._me +@add_metaclass(MetaPersonTeam) class PersonTeam(BaseWrapper): ''' Wrapper class around a LP person or team object. ''' - __metaclass__ = MetaPersonTeam resource_type = ( 'person', @@ -716,7 +739,7 @@ class PersonTeam(BaseWrapper): sourcepackagename=package, ) canUpload = True - except HTTPError, e: + except HTTPError as e: if e.response.status == 403: canUpload = False else: From 1558b91dded6cdf5d5455c130b3241c667580bd0 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 20:34:04 +0000 Subject: [PATCH 10/35] misc.py --- ubuntutools/misc.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/ubuntutools/misc.py b/ubuntutools/misc.py index 8e8fa98..dc6d2e0 100644 --- a/ubuntutools/misc.py +++ b/ubuntutools/misc.py @@ -22,6 +22,8 @@ # # ################################################################## +from __future__ import print_function + # Modules. import locale import os @@ -66,8 +68,8 @@ def system_distribution_chain(): break _system_distribution_chain.append(parent) except Exception: - print ('Error: Could not determine the parent of the ' - 'distribution %s' % _system_distribution_chain[-1]) + print(('Error: Could not determine the parent of the ' + 'distribution %s' % _system_distribution_chain[-1])) return [] return _system_distribution_chain @@ -92,8 +94,8 @@ def host_architecture(): stderr=PIPE).communicate()[0].split() if not arch or 'not found' in arch[0]: - print 'Error: Not running on a Debian based system; could not ' \ - 'detect its architecture.' + print('Error: Not running on a Debian based system; could not ' \ + 'detect its architecture.') return None return arch[0] @@ -106,13 +108,13 @@ def readlist(filename, uniq=True): """ if not os.path.isfile(filename): - print 'File "%s" does not exist.' % filename + print('File "%s" does not exist.' % filename) return False content = open(filename).read().replace('\n', ' ').replace(',', ' ') if not content.strip(): - print 'File "%s" is empty.' % filename + print('File "%s" is empty.' % filename) return False items = [item for item in content.split() if item] @@ -149,8 +151,8 @@ def split_release_pocket(release, default='Release'): def require_utf8(): '''Can be called by programs that only function in UTF-8 locales''' if locale.getpreferredencoding() != 'UTF-8': - print >> sys.stderr, ("This program only functions in a UTF-8 locale. " - "Aborting.") + print(("This program only functions in a UTF-8 locale. " + "Aborting."), file=sys.stderr) sys.exit(1) From ea74634e93dce260ffeac2437ee7f383df33c006 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 20:44:02 +0000 Subject: [PATCH 11/35] questions --- ubuntutools/question.py | 43 +++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/ubuntutools/question.py b/ubuntutools/question.py index 74308e6..a9408c2 100644 --- a/ubuntutools/question.py +++ b/ubuntutools/question.py @@ -16,10 +16,15 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import print_function + import tempfile import os import re import sys +if sys.version_info[0] < 3: + input = raw_input + import ubuntutools.subprocess @@ -56,9 +61,9 @@ class Question(object): selected = None while selected not in self.options: try: - selected = raw_input(question).strip().lower() + selected = input(question).strip().lower() except (EOFError, KeyboardInterrupt): - print '\nAborting as requested.' + print('\nAborting as requested.') sys.exit(1) if selected == "": selected = default @@ -68,8 +73,8 @@ class Question(object): if selected == option[0]: selected = option if selected not in self.options: - print "Please answer the question with " + \ - self.get_options() + "." + print("Please answer the question with " + \ + self.get_options() + ".") return selected @@ -86,9 +91,9 @@ def input_number(question, min_number, max_number, default=None): selected = None while selected < min_number or selected > max_number: try: - selected = raw_input(question).strip() + selected = input(question).strip() except (EOFError, KeyboardInterrupt): - print '\nAborting as requested.' + print('\nAborting as requested.') sys.exit(1) if default and selected == "": selected = default @@ -96,10 +101,10 @@ def input_number(question, min_number, max_number, default=None): try: selected = int(selected) if selected < min_number or selected > max_number: - print "Please input a number between %i and %i." % \ - (min_number, max_number) + print("Please input a number between %i and %i." % \ + (min_number, max_number)) except ValueError: - print "Please input a number." + print("Please input a number.") assert type(selected) == int return selected @@ -113,9 +118,9 @@ def confirmation_prompt(message=None, action=None): action = 'continue' message = 'Press [Enter] to %s. Press [Ctrl-C] to abort now.' % action try: - raw_input(message) + input(message) except (EOFError, KeyboardInterrupt): - print '\nAborting as requested.' + print('\nAborting as requested.') sys.exit(1) @@ -129,9 +134,9 @@ class EditFile(object): def edit(self, optional=False): if optional: - print "\n\nCurrently the %s looks like:" % self.description + print("\n\nCurrently the %s looks like:" % self.description) with open(self.filename, 'r') as f: - print f.read() + print(f.read()) if YesNoQuestion().ask("Edit", "no") == "no": return @@ -150,12 +155,12 @@ class EditFile(object): placeholders_present = True if placeholders_present: - print ("Placeholders still present in the %s. " - "Please replace them with useful information." - % self.description) + print("Placeholders still present in the %s. " + "Please replace them with useful information." + % self.description) confirmation_prompt(action='edit again') elif not modified: - print "The %s was not modified" % self.description + print("The %s was not modified" % self.description) if YesNoQuestion().ask("Edit again", "yes") == "no": done = True elif self.check_edit(): @@ -189,8 +194,8 @@ class EditBugReport(EditFile): report = f.read().decode('utf-8') if self.split_re.match(report) is None: - print ("The %s doesn't start with 'Summary:' and 'Description:' " - "blocks" % self.description) + print("The %s doesn't start with 'Summary:' and 'Description:' " + "blocks" % self.description) confirmation_prompt('edit again') return False return True From 1d2f7f6d0db538c9c1734721b0063ad455531f7b Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 20:45:58 +0000 Subject: [PATCH 12/35] rs/lp --- ubuntutools/requestsync/lp.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/ubuntutools/requestsync/lp.py b/ubuntutools/requestsync/lp.py index 73f5d59..0df7139 100644 --- a/ubuntutools/requestsync/lp.py +++ b/ubuntutools/requestsync/lp.py @@ -20,6 +20,8 @@ # Please see the /usr/share/common-licenses/GPL-2 file for the full text # of the GNU General Public License license. +from __future__ import print_function + import re from debian.deb822 import Changes @@ -39,7 +41,7 @@ def get_debian_srcpkg(name, release): try: release = DebianDistroInfo().codename(release, None, release) - except DistroDataOutdated, e: + except DistroDataOutdated as e: Logger.warn(e) return debian_archive.getSourcePackage(name, release) @@ -71,11 +73,11 @@ def need_sponsorship(name, component, release): need_sponsor = not PersonTeam.me.canUploadPackage(archive, distroseries, name, component) if need_sponsor: - print '''You are not able to upload this package directly to Ubuntu. + print('''You are not able to upload this package directly to Ubuntu. Your sync request shall require an approval by a member of the appropriate sponsorship team, who shall be subscribed to this bug report. This must be done before it can be processed by a member of the Ubuntu Archive -team.''' +team.''') confirmation_prompt() return need_sponsor @@ -98,12 +100,12 @@ def check_existing_reports(srcpkg): for bug in pkg_bug_list: # check for Sync or sync and the package name if not bug.is_complete and 'ync %s' % srcpkg in bug.title: - print ('The following bug could be a possible duplicate sync bug ' - 'on Launchpad:\n' - ' * %s (%s)\n' - 'Please check the above URL to verify this before ' - 'continuing.' - % (bug.title, bug.web_link)) + print('The following bug could be a possible duplicate sync bug ' + 'on Launchpad:\n' + ' * %s (%s)\n' + 'Please check the above URL to verify this before ' + 'continuing.' + % (bug.title, bug.web_link)) confirmation_prompt() def get_ubuntu_delta_changelog(srcpkg): @@ -127,7 +129,7 @@ def get_ubuntu_delta_changelog(srcpkg): break try: response, body = Http().request(changes_url) - except HttpLib2Error, e: + except HttpLib2Error as e: Logger.error(str(e)) break if response.status != 200: @@ -156,8 +158,8 @@ def post_bug(srcpkg, subscribe, status, bugtitle, bugtext): Use the LP API to file the sync request. ''' - print ('The final report is:\nSummary: %s\nDescription:\n%s\n' - % (bugtitle, bugtext)) + print('The final report is:\nSummary: %s\nDescription:\n%s\n' + % (bugtitle, bugtext)) confirmation_prompt() if srcpkg: @@ -181,5 +183,5 @@ def post_bug(srcpkg, subscribe, status, bugtitle, bugtext): bug.subscribe(person = PersonTeam(subscribe)()) - print ('Sync request filed as bug #%i: %s' - % (bug.id, bug.web_link)) + print('Sync request filed as bug #%i: %s' + % (bug.id, bug.web_link)) From 3f512ee337351116dcf232475c439eae979aa5c0 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 20:48:28 +0000 Subject: [PATCH 13/35] rs/mail --- ubuntutools/requestsync/mail.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/ubuntutools/requestsync/mail.py b/ubuntutools/requestsync/mail.py index 11e2768..1abb395 100644 --- a/ubuntutools/requestsync/mail.py +++ b/ubuntutools/requestsync/mail.py @@ -20,6 +20,8 @@ # Please see the /usr/share/common-licenses/GPL-2 file for the full text # of the GNU General Public License license. +from __future__ import print_function + import os import re import sys @@ -27,6 +29,10 @@ import smtplib import socket import tempfile +if sys.version_info[0] >= 3: + basestring = str + unicode = str + from debian.changelog import Changelog, Version from distro_info import DebianDistroInfo, DistroDataOutdated @@ -51,7 +57,7 @@ def _get_srcpkg(distro, name, release): debian_info = DebianDistroInfo() try: release = debian_info.codename(release, default=release) - except DistroDataOutdated, e: + except DistroDataOutdated as e: Logger.warn(e) lines = list(rmadison(distro, name, suite=release, arch='source')) @@ -86,9 +92,9 @@ def check_existing_reports(srcpkg): ''' Point the user to the URL to manually check for duplicate bug reports. ''' - print ('Please check on ' - 'https://bugs.launchpad.net/ubuntu/+source/%s/+bugs\n' - 'for duplicate sync requests before continuing.' % srcpkg) + print('Please check on ' + 'https://bugs.launchpad.net/ubuntu/+source/%s/+bugs\n' + 'for duplicate sync requests before continuing.' % srcpkg) confirmation_prompt() def get_ubuntu_delta_changelog(srcpkg): @@ -164,7 +170,7 @@ Content-Type: text/plain; charset=UTF-8 %s''' % (myemailaddr, to, bugtitle, signed_report) - print 'The final report is:\n%s' % mail + print('The final report is:\n%s' % mail) confirmation_prompt() # save mail in temporary file @@ -184,11 +190,11 @@ Content-Type: text/plain; charset=UTF-8 mailserver_port) s = smtplib.SMTP(mailserver_host, mailserver_port) break - except socket.error, s: + except socket.error as s: Logger.error('Could not connect to %s:%s: %s (%i)', mailserver_host, mailserver_port, s[1], s[0]) return - except smtplib.SMTPConnectError, s: + except smtplib.SMTPConnectError as s: Logger.error('Could not connect to %s:%s: %s (%i)', mailserver_host, mailserver_port, s[1], s[0]) if s.smtp_code == 421: @@ -215,7 +221,7 @@ Content-Type: text/plain; charset=UTF-8 os.remove(backup.name) Logger.normal('Sync request mailed.') break - except smtplib.SMTPRecipientsRefused, smtperror: + except smtplib.SMTPRecipientsRefused as smtperror: smtp_code, smtp_message = smtperror.recipients[to] Logger.error('Error while sending: %i, %s', smtp_code, smtp_message) if smtp_code == 450: @@ -223,7 +229,7 @@ Content-Type: text/plain; charset=UTF-8 '[Enter] to retry. Press [Ctrl-C] to abort now.') else: return - except smtplib.SMTPResponseException, e: + except smtplib.SMTPResponseException as e: Logger.error('Error while sending: %i, %s', e.smtp_code, e.smtp_error) return From e20d1257091bdc1f695eeb5632bc41065188aabc Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 20:51:24 +0000 Subject: [PATCH 14/35] bugtask --- ubuntutools/sponsor_patch/bugtask.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ubuntutools/sponsor_patch/bugtask.py b/ubuntutools/sponsor_patch/bugtask.py index ce8d90e..6340a4e 100644 --- a/ubuntutools/sponsor_patch/bugtask.py +++ b/ubuntutools/sponsor_patch/bugtask.py @@ -17,7 +17,11 @@ import os import re -import urllib +try: + from urllib.parse import unquote + from urllib.request import urlretrieve +except ImportError: + from urllib import unquote, urlretrieve import debian.debian_support import distro_info @@ -63,7 +67,7 @@ class BugTask(object): source_files = self.get_source().sourceFileUrls() dsc_file = "" for url in source_files: - filename = urllib.unquote(os.path.basename(url)) + filename = unquote(os.path.basename(url)) Logger.info("Downloading %s..." % (filename)) # HttpLib2 isn't suitable for large files (it reads into memory), # but we want its https certificate validation on the .dsc @@ -75,7 +79,7 @@ class BugTask(object): dsc_file = os.path.join(os.getcwd(), filename) else: - urllib.urlretrieve(url, filename) + urlretrieve(url, filename) assert os.path.isfile(dsc_file), "%s does not exist." % (dsc_file) return dsc_file From 194d23e878afb11ddc456a01764227d75c06f978 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 20:52:17 +0000 Subject: [PATCH 15/35] patch --- ubuntutools/sponsor_patch/patch.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ubuntutools/sponsor_patch/patch.py b/ubuntutools/sponsor_patch/patch.py index fd2575d..f46284c 100644 --- a/ubuntutools/sponsor_patch/patch.py +++ b/ubuntutools/sponsor_patch/patch.py @@ -21,6 +21,7 @@ import re from ubuntutools import subprocess from ubuntutools.logger import Logger from ubuntutools.sponsor_patch.question import ask_for_manual_fixing +from functools import reduce class Patch(object): """This object represents a patch that can be downloaded from Launchpad.""" From 57ea2cc410577ae0acf46e207608ec2836e24976 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 20:52:51 +0000 Subject: [PATCH 16/35] question --- ubuntutools/sponsor_patch/question.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ubuntutools/sponsor_patch/question.py b/ubuntutools/sponsor_patch/question.py index 363153f..1594eed 100644 --- a/ubuntutools/sponsor_patch/question.py +++ b/ubuntutools/sponsor_patch/question.py @@ -15,6 +15,8 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import print_function + import sys from ubuntutools.question import Question, YesNoQuestion @@ -43,5 +45,5 @@ def ask_for_manual_fixing(): def user_abort(): """Print abort and quit the program.""" - print "User abort." + print("User abort.") sys.exit(2) From c8ec463f7ae42028756614a03e1a701d9a6428c8 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 20:54:00 +0000 Subject: [PATCH 17/35] sp/source_package --- ubuntutools/sponsor_patch/source_package.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/ubuntutools/sponsor_patch/source_package.py b/ubuntutools/sponsor_patch/source_package.py index 602c2bb..69910ec 100644 --- a/ubuntutools/sponsor_patch/source_package.py +++ b/ubuntutools/sponsor_patch/source_package.py @@ -15,6 +15,8 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import print_function + import os import re import sys @@ -301,7 +303,7 @@ class SourcePackage(object): bug title.""" if not task.title_contains(self._version): - print "Bug #%i title: %s" % (bug_number, task.get_bug_title()) + print("Bug #%i title: %s" % (bug_number, task.get_bug_title())) msg = "Is %s %s the version that should be synced" % (self._package, self._version) answer = YesNoQuestion().ask(msg, "no") @@ -370,16 +372,16 @@ class SourcePackage(object): """Print things that should be checked before uploading a package.""" lintian_filename = self._run_lintian() - print "\nPlease check %s %s carefully:" % (self._package, self._version) + print("\nPlease check %s %s carefully:" % (self._package, self._version)) if os.path.isfile(self._debdiff_filename): - print "file://" + self._debdiff_filename - print "file://" + lintian_filename + print("file://" + self._debdiff_filename) + print("file://" + lintian_filename) if self._build_log: - print "file://" + self._build_log + print("file://" + self._build_log) harvest = Harvest(self._package) if harvest.data: - print harvest.report() + print(harvest.report()) def reload_changelog(self): """Reloads debian/changelog and updates the version. @@ -393,7 +395,7 @@ class SourcePackage(object): try: self._changelog.parse_changelog(file("debian/changelog"), max_blocks=1, strict=True) - except debian.changelog.ChangelogParseError, error: + except debian.changelog.ChangelogParseError as error: Logger.error("The changelog entry doesn't validate: %s", str(error)) ask_for_manual_fixing() return False From 8c6371a416e0e58e4003e007de4272088d9972a3 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 20:56:13 +0000 Subject: [PATCH 18/35] sp/sp --- ubuntutools/sponsor_patch/sponsor_patch.py | 23 +++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/ubuntutools/sponsor_patch/sponsor_patch.py b/ubuntutools/sponsor_patch/sponsor_patch.py index 510d5e1..715ce32 100644 --- a/ubuntutools/sponsor_patch/sponsor_patch.py +++ b/ubuntutools/sponsor_patch/sponsor_patch.py @@ -15,6 +15,11 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import print_function + +if sys.version_info[0] < 3: + range = xrange + import os import pwd import shutil @@ -81,11 +86,11 @@ def edit_source(): # Spawn shell to allow modifications cmd = [get_user_shell()] Logger.command(cmd) - print """An interactive shell was launched in + print("""An interactive shell was launched in file://%s Edit your files. When you are done, exit the shell. If you wish to abort the process, exit the shell such that it returns an exit code other than zero. -""" % (os.getcwd()), +""" % (os.getcwd()), end=' ') returncode = subprocess.call(cmd) if returncode != 0: Logger.error("Shell exited with exit value %i." % (returncode)) @@ -113,10 +118,10 @@ def ask_for_patch_or_branch(bug, attached_patches, linked_branches): i = 0 for linked_branch in linked_branches: i += 1 - print "%i) %s" % (i, linked_branch.display_name) + print("%i) %s" % (i, linked_branch.display_name)) for attached_patch in attached_patches: i += 1 - print "%i) %s" % (i, attached_patch.title) + print("%i) %s" % (i, attached_patch.title)) selected = input_number("Which branch or patch do you want to download", 1, i, i) if selected <= len(linked_branches): @@ -220,9 +225,9 @@ def get_open_ubuntu_bug_task(launchpad, bug, branch=None): else: Logger.normal("https://launchpad.net/bugs/%i has %i Ubuntu tasks:" \ % (bug_id, len(ubuntu_tasks))) - for i in xrange(len(ubuntu_tasks)): - print "%i) %s" % (i + 1, - ubuntu_tasks[i].get_package_and_series()) + for i in range(len(ubuntu_tasks)): + print("%i) %s" % (i + 1, + ubuntu_tasks[i].get_package_and_series())) selected = input_number("To which Ubuntu task does the patch belong", 1, len(ubuntu_tasks)) task = ubuntu_tasks[selected - 1] @@ -235,7 +240,7 @@ def _create_and_change_into(workdir): if not os.path.isdir(workdir): try: os.makedirs(workdir) - except os.error, error: + except os.error as error: Logger.error("Failed to create the working directory %s [Errno " \ "%i]: %s." % (workdir, error.errno, error.strerror)) sys.exit(1) @@ -248,7 +253,7 @@ def _update_maintainer_field(): Logger.command(["update-maintainer"]) try: update_maintainer("debian", Logger.verbose) - except MaintainerUpdateException, e: + except MaintainerUpdateException as e: Logger.error("update-maintainer failed: %s", str(e)) sys.exit(1) From e959384f02acaa54457b7344b3c95aaaae9e41c6 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 20:57:17 +0000 Subject: [PATCH 19/35] update_maintainer --- ubuntutools/update_maintainer.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/ubuntutools/update_maintainer.py b/ubuntutools/update_maintainer.py index 2b1ff59..82d6e4d 100644 --- a/ubuntutools/update_maintainer.py +++ b/ubuntutools/update_maintainer.py @@ -14,6 +14,8 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import print_function + """This module is for updating the Maintainer field of an Ubuntu package.""" import os @@ -125,7 +127,7 @@ def _find_files(debian_directory, verbose): if os.path.isfile(rules_file) and \ 'XSBC-Original-' in open(rules_file).read(): if verbose: - print "XSBC-Original is managed by 'rules' file. Doing nothing." + print("XSBC-Original is managed by 'rules' file. Doing nothing.") control_files = [] return (changelog_file, control_files) @@ -144,7 +146,7 @@ def update_maintainer(debian_directory, verbose=False): """ try: changelog_file, control_files = _find_files(debian_directory, verbose) - except MaintainerUpdateException, e: + except MaintainerUpdateException as e: Logger.error(str(e)) raise @@ -159,8 +161,8 @@ def update_maintainer(debian_directory, verbose=False): if original_maintainer.strip().lower() in _PREVIOUS_UBUNTU_MAINTAINER: if verbose: - print "The old maintainer was: %s" % original_maintainer - print "Resetting as: %s" % _UBUNTU_MAINTAINER + print("The old maintainer was: %s" % original_maintainer) + print("Resetting as: %s" % _UBUNTU_MAINTAINER) control.set_maintainer(_UBUNTU_MAINTAINER) control.save() continue @@ -173,7 +175,7 @@ def update_maintainer(debian_directory, verbose=False): if distribution in ("stable", "testing", "unstable", "experimental"): if verbose: - print "The package targets Debian. Doing nothing." + print("The package targets Debian. Doing nothing.") return if control.get_original_maintainer() is not None: @@ -181,8 +183,8 @@ def update_maintainer(debian_directory, verbose=False): control.get_original_maintainer()) if verbose: - print "The original maintainer is: %s" % original_maintainer - print "Resetting as: %s" % _UBUNTU_MAINTAINER + print("The original maintainer is: %s" % original_maintainer) + print("Resetting as: %s" % _UBUNTU_MAINTAINER) control.set_original_maintainer(original_maintainer) control.set_maintainer(_UBUNTU_MAINTAINER) control.save() @@ -194,7 +196,7 @@ def restore_maintainer(debian_directory, verbose=False): """Restore the original maintainer""" try: changelog_file, control_files = _find_files(debian_directory, verbose) - except MaintainerUpdateException, e: + except MaintainerUpdateException as e: Logger.error(str(e)) raise @@ -204,7 +206,7 @@ def restore_maintainer(debian_directory, verbose=False): if not orig_maintainer: continue if verbose: - print "Restoring original maintainer: %s" % orig_maintainer + print("Restoring original maintainer: %s" % orig_maintainer) control.set_maintainer(orig_maintainer) control.remove_original_maintainer() control.save() From 509b612b0fa7101b0bd3a6046a5b3684110f67c6 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 21:03:05 +0000 Subject: [PATCH 20/35] fix sp/sp --- ubuntutools/sponsor_patch/sponsor_patch.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ubuntutools/sponsor_patch/sponsor_patch.py b/ubuntutools/sponsor_patch/sponsor_patch.py index 715ce32..eff9142 100644 --- a/ubuntutools/sponsor_patch/sponsor_patch.py +++ b/ubuntutools/sponsor_patch/sponsor_patch.py @@ -17,14 +17,14 @@ from __future__ import print_function -if sys.version_info[0] < 3: - range = xrange - import os import pwd import shutil import sys +if sys.version_info[0] < 3: + range = xrange + from distro_info import UbuntuDistroInfo from launchpadlib.launchpad import Launchpad From 8b5db046be3524131c823c48e6fa5474b6d5a266 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 21:03:27 +0000 Subject: [PATCH 21/35] t/t_config --- ubuntutools/test/test_config.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/ubuntutools/test/test_config.py b/ubuntutools/test/test_config.py index a48902f..f5ae418 100644 --- a/ubuntutools/test/test_config.py +++ b/ubuntutools/test/test_config.py @@ -15,12 +15,15 @@ # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -import __builtin__ +try: + import builtins +except ImportError: + import __builtin__ import os import sys import locale from io import BytesIO -from StringIO import StringIO +from io import StringIO import mock @@ -47,6 +50,8 @@ class ConfigTestCase(unittest.TestCase): def setUp(self): super(ConfigTestCase, self).setUp() + if sys.version_info[0] < 3: + self.assertRegex = self.assertRegexpMatches m = mock.mock_open() m.side_effect = self._fake_open patcher = mock.patch('__builtin__.open', m) @@ -103,8 +108,8 @@ REPEAT=yes errs = Logger.stderr.getvalue().strip() Logger.stderr = StringIO() self.assertEqual(len(errs.splitlines()), 1) - self.assertRegexpMatches(errs, - r'Warning: Cannot parse.*\bCOMMAND_EXECUTION=a') + self.assertRegex(errs, + r'Warning: Cannot parse.*\bCOMMAND_EXECUTION=a') def get_value(self, *args, **kwargs): config = UDTConfig(prefix='TEST') @@ -143,8 +148,8 @@ REPEAT=yes errs = Logger.stderr.getvalue().strip() Logger.stderr = StringIO() self.assertEqual(len(errs.splitlines()), 1) - self.assertRegexpMatches(errs, - r'deprecated.*\bCOMPATFOOBAR\b.*\bTEST_QUX\b') + self.assertRegex(errs, + r'deprecated.*\bCOMPATFOOBAR\b.*\bTEST_QUX\b') def test_boolean(self): self._config_files['user'] = "TEST_BOOLEAN=yes" @@ -156,7 +161,7 @@ REPEAT=yes def test_nonpackagewide(self): self._config_files['user'] = 'UBUNTUTOOLS_FOOBAR=a' - self.assertEquals(self.get_value('FOOBAR'), None) + self.assertEqual(self.get_value('FOOBAR'), None) class UbuEmailTestCase(unittest.TestCase): From a7f4fc202bd768199b8a016c5df0645b9c7e6330 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 21:06:44 +0000 Subject: [PATCH 22/35] fix test_config --- ubuntutools/test/test_config.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ubuntutools/test/test_config.py b/ubuntutools/test/test_config.py index f5ae418..f0c3d97 100644 --- a/ubuntutools/test/test_config.py +++ b/ubuntutools/test/test_config.py @@ -23,7 +23,10 @@ import os import sys import locale from io import BytesIO -from io import StringIO +try: + from StringIO import StringIO +except: + from io import StringIO import mock From dae4c18c9e5f2fa5981758200caecaa762f38e1b Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 21:09:44 +0000 Subject: [PATCH 23/35] update_maintainer --- ubuntutools/test/test_update_maintainer.py | 55 +++++++++++++--------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/ubuntutools/test/test_update_maintainer.py b/ubuntutools/test/test_update_maintainer.py index 40be54a..e951ae5 100644 --- a/ubuntutools/test/test_update_maintainer.py +++ b/ubuntutools/test/test_update_maintainer.py @@ -16,9 +16,16 @@ """Test suite for ubuntutools.update_maintainer""" -import __builtin__ +try: + import builtins +except ImportError: + import __builtin__ +try: + from StringIO import StringIO +except: + from io import StringIO + import os -import StringIO import sys import mock @@ -210,12 +217,14 @@ class UpdateMaintainerTestCase(unittest.TestCase): (mode == "r" and self._files[base] is None)): raise IOError("No such file or directory: '%s'" % filename) if mode == "w": - self._files[base] = StringIO.StringIO() + self._files[base] = StringIO() self._files[base].close = lambda: None return self._files[base] #pylint: disable=C0103 def setUp(self): + if sys.version_info[0] < 3: + self.assertRegex = self.assertRegexpMatches m = mock.mock_open() m.side_effect = self._fake_open patcher = mock.patch('__builtin__.open', m) @@ -225,9 +234,9 @@ class UpdateMaintainerTestCase(unittest.TestCase): patcher = mock.patch('os.path.isfile', m) self.addCleanup(patcher.stop) patcher.start() - self._files["rules"] = StringIO.StringIO(_SIMPLE_RULES) - Logger.stdout = StringIO.StringIO() - Logger.stderr = StringIO.StringIO() + self._files["rules"] = StringIO(_SIMPLE_RULES) + Logger.stdout = StringIO() + Logger.stderr = StringIO() def tearDown(self): self.assertEqual(Logger.stdout.getvalue(), '') @@ -242,8 +251,8 @@ class UpdateMaintainerTestCase(unittest.TestCase): #pylint: enable=C0103 def test_debian_package(self): """Test: Don't update Maintainer field if target is Debian.""" - self._files["changelog"] = StringIO.StringIO(_UNSTABLE_CHANGELOG) - self._files["control"] = StringIO.StringIO(_ABP_CONTROL) + self._files["changelog"] = StringIO(_UNSTABLE_CHANGELOG) + self._files["control"] = StringIO(_ABP_CONTROL) update_maintainer(self._directory) self.assertEqual(self._files["control"].getvalue(), _ABP_CONTROL) @@ -252,52 +261,52 @@ class UpdateMaintainerTestCase(unittest.TestCase): The Maintainer field needs to be update even if XSBC-Original-Maintainer has an @ubuntu.com address.""" - self._files["changelog"] = StringIO.StringIO(_LUCID_CHANGELOG) - self._files["control"] = StringIO.StringIO(_AXIS2C_CONTROL) + self._files["changelog"] = StringIO(_LUCID_CHANGELOG) + self._files["control"] = StringIO(_AXIS2C_CONTROL) update_maintainer(self._directory) self.assertEqual(self._files["control"].getvalue(), _AXIS2C_UPDATED) warnings = Logger.stderr.getvalue().strip() - Logger.stderr = StringIO.StringIO() + Logger.stderr = StringIO() self.assertEqual(len(warnings.splitlines()), 1) - self.assertRegexpMatches(warnings, "Warning: Overwriting original " + self.assertRegex(warnings, "Warning: Overwriting original " "maintainer: Soren Hansen " "") def test_update_maintainer(self): """Test: Update Maintainer field.""" - self._files["changelog"] = StringIO.StringIO(_LUCID_CHANGELOG) - self._files["control"] = StringIO.StringIO(_ABP_CONTROL) + self._files["changelog"] = StringIO(_LUCID_CHANGELOG) + self._files["control"] = StringIO(_ABP_CONTROL) update_maintainer(self._directory) self.assertEqual(self._files["control"].getvalue(), _ABP_UPDATED) def test_update_old_maintainer(self): """Test: Update old MOTU address.""" - self._files["changelog"] = StringIO.StringIO(_UNSTABLE_CHANGELOG) - self._files["control.in"] = StringIO.StringIO(_ABP_OLD_MAINTAINER) + self._files["changelog"] = StringIO(_UNSTABLE_CHANGELOG) + self._files["control.in"] = StringIO(_ABP_OLD_MAINTAINER) update_maintainer(self._directory, True) self.assertEqual(self._files["control.in"].getvalue(), _ABP_UPDATED) def test_comments_in_control(self): """Test: Update Maintainer field in a control file containing comments.""" - self._files["changelog"] = StringIO.StringIO(_LUCID_CHANGELOG) - self._files["control"] = StringIO.StringIO(_SEAHORSE_PLUGINS_CONTROL) + self._files["changelog"] = StringIO(_LUCID_CHANGELOG) + self._files["control"] = StringIO(_SEAHORSE_PLUGINS_CONTROL) update_maintainer(self._directory) self.assertEqual(self._files["control"].getvalue(), _SEAHORSE_PLUGINS_UPDATED) def test_skip_smart_rules(self): """Test: Skip update when XSBC-Original in debian/rules.""" - self._files["changelog"] = StringIO.StringIO(_LUCID_CHANGELOG) - self._files["control"] = StringIO.StringIO(_ABP_CONTROL) - self._files["rules"] = StringIO.StringIO(_COMPLEX_RULES) + self._files["changelog"] = StringIO(_LUCID_CHANGELOG) + self._files["control"] = StringIO(_ABP_CONTROL) + self._files["rules"] = StringIO(_COMPLEX_RULES) update_maintainer(self._directory) self.assertEqual(self._files["control"].getvalue(), _ABP_CONTROL) def test_missing_rules(self): """Test: Skip XSBC-Original test when debian/rules is missing.""" - self._files["changelog"] = StringIO.StringIO(_LUCID_CHANGELOG) - self._files["control"] = StringIO.StringIO(_ABP_CONTROL) + self._files["changelog"] = StringIO(_LUCID_CHANGELOG) + self._files["control"] = StringIO(_ABP_CONTROL) self._files["rules"] = None update_maintainer(self._directory) self.assertEqual(self._files["control"].getvalue(), _ABP_UPDATED) From b8cf7b113e3c780bdfdaefb90db2068c81476c36 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 21:11:00 +0000 Subject: [PATCH 24/35] logger --- ubuntutools/test/test_logger.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ubuntutools/test/test_logger.py b/ubuntutools/test/test_logger.py index 91cbbed..36b0a72 100644 --- a/ubuntutools/test/test_logger.py +++ b/ubuntutools/test/test_logger.py @@ -14,7 +14,10 @@ # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -import StringIO +try: + from StringIO import StringIO +except: + from io import StringIO import sys from ubuntutools.logger import Logger @@ -23,8 +26,8 @@ from ubuntutools.test import unittest class LoggerTestCase(unittest.TestCase): def setUp(self): - Logger.stdout = StringIO.StringIO() - Logger.stderr = StringIO.StringIO() + Logger.stdout = StringIO() + Logger.stderr = StringIO() self._script_name = Logger.script_name Logger.script_name = 'test' self._verbose = Logger.verbose From d86cacddf90dec2e641d1e2d12b40d02f1f2a056 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 21:18:01 +0000 Subject: [PATCH 25/35] finish no-regress pre-port. --- ubuntutools/test/test_archive.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/ubuntutools/test/test_archive.py b/ubuntutools/test/test_archive.py index 9c792f5..17c2346 100644 --- a/ubuntutools/test/test_archive.py +++ b/ubuntutools/test/test_archive.py @@ -14,17 +14,26 @@ # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -from __future__ import with_statement -import __builtin__ +try: + import builtins +except ImportError: + import __builtin__ import os.path import shutil -import StringIO +try: + from StringIO import StringIO +except: + from io import StringIO from io import BytesIO import tempfile import types -import urllib2 - +try: + from urllib.request import OpenerDirector, urlopen + from urllib.error import HTTPError +except ImportError: + from urllib2 import OpenerDirector, urlopen + from urllib2 import HTTPError import debian.deb822 import httplib2 import mock @@ -94,7 +103,7 @@ class LocalSourcePackageTestCase(unittest.TestCase): self.mock_http = self._stubout('httplib2.Http.request') self.mock_http.side_effect = self.request_proxy - self.url_opener = mock.MagicMock(spec=urllib2.OpenerDirector) + self.url_opener = mock.MagicMock(spec=OpenerDirector) self.url_opener.open.side_effect = self.urlopen_proxy # Silence the tests a little: @@ -114,7 +123,7 @@ class LocalSourcePackageTestCase(unittest.TestCase): if destname is None: destname = os.path.basename(url) destpath = os.path.join(os.path.abspath('test-data'), destname) - return urllib2.urlopen('file://' + destpath) + return urlopen('file://' + destpath) def urlopen_file(self, filename): "Wrapper for urlopen_proxy for named files" @@ -122,11 +131,11 @@ class LocalSourcePackageTestCase(unittest.TestCase): def urlopen_null(self, url): "urlopen for zero length files" - return StringIO.StringIO('') + return StringIO('') def urlopen_404(self, url): "urlopen for errors" - raise urllib2.HTTPError(url, 404, "Not Found", {}, None) + raise HTTPError(url, 404, "Not Found", {}, None) def request_proxy(self, url, destname=None): "httplib2 proxy for grabbing the file from test-data" @@ -212,7 +221,7 @@ class LocalSourcePackageTestCase(unittest.TestCase): self.urlopen_proxy] def _callable_iter(*args, **kwargs): return sequence.pop(0)(*args, **kwargs) - url_opener = mock.MagicMock(spec=urllib2.OpenerDirector) + url_opener = mock.MagicMock(spec=OpenerDirector) url_opener.open.side_effect = _callable_iter pkg = self.SourcePackage('example', '1.0-1', 'main', @@ -249,7 +258,7 @@ class DebianLocalSourcePackageTestCase(LocalSourcePackageTestCase): self.urlopen_proxy] def _callable_iter(*args, **kwargs): return sequence.pop(0)(*args, **kwargs) - url_opener = mock.MagicMock(spec=urllib2.OpenerDirector) + url_opener = mock.MagicMock(spec=OpenerDirector) url_opener.open.side_effect = _callable_iter pkg = self.SourcePackage('example', '1.0-1', 'main', From ddabeed530a0da193df4d6a55aa0aa54d0114e10 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 21:34:13 +0000 Subject: [PATCH 26/35] Fix ups --- ubuntutools/archive.py | 2 +- ubuntutools/test/test_help.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ubuntutools/archive.py b/ubuntutools/archive.py index 641c016..314f3b4 100644 --- a/ubuntutools/archive.py +++ b/ubuntutools/archive.py @@ -308,7 +308,7 @@ class SourcePackage(object): "Write dsc file to workdir" if self._dsc is None: self.pull_dsc() - with open(self.dsc_pathname, 'w') as f: + with open(self.dsc_pathname, 'wb') as f: f.write(self.dsc.raw_text) def _download_file(self, url, filename): diff --git a/ubuntutools/test/test_help.py b/ubuntutools/test/test_help.py index 819630c..6c797ea 100644 --- a/ubuntutools/test/test_help.py +++ b/ubuntutools/test/test_help.py @@ -45,6 +45,7 @@ class HelpTestCase(unittest.TestCase): null = open('/dev/null', 'r') process = subprocess.Popen(['./' + script, '--help'], close_fds=True, stdin=null, + universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) started = time.time() @@ -57,7 +58,10 @@ class HelpTestCase(unittest.TestCase): while time.time() - started < TIMEOUT: for fd in select.select(fds, [], fds, TIMEOUT)[0]: - out.append(os.read(fd, 1024)) + output = os.read(fd, 1024) + if not isinstance(output, str): + output = output.decode('utf-8') + out.append(output) if process.poll() is not None: break From 1bab6441915cde2acd398b26435c09b710d83603 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 21:53:00 +0000 Subject: [PATCH 27/35] Conf fixes --- ubuntutools/config.py | 2 +- ubuntutools/test/test_config.py | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/ubuntutools/config.py b/ubuntutools/config.py index 6e11e4a..f047ae4 100644 --- a/ubuntutools/config.py +++ b/ubuntutools/config.py @@ -179,6 +179,6 @@ def ubu_email(name=None, email=None, export=True): encoding = locale.getdefaultlocale()[1] if not encoding: encoding = 'utf-8' - if name: + if name and isinstance(name, bytes): name = name.decode(encoding) return name, email diff --git a/ubuntutools/test/test_config.py b/ubuntutools/test/test_config.py index f0c3d97..b118b05 100644 --- a/ubuntutools/test/test_config.py +++ b/ubuntutools/test/test_config.py @@ -22,7 +22,6 @@ except ImportError: import os import sys import locale -from io import BytesIO try: from StringIO import StringIO except: @@ -49,7 +48,7 @@ class ConfigTestCase(unittest.TestCase): } if filename not in files: raise IOError("No such file or directory: '%s'" % filename) - return BytesIO(files[filename]) + return StringIO(files[filename]) def setUp(self): super(ConfigTestCase, self).setUp() @@ -57,7 +56,11 @@ class ConfigTestCase(unittest.TestCase): self.assertRegex = self.assertRegexpMatches m = mock.mock_open() m.side_effect = self._fake_open - patcher = mock.patch('__builtin__.open', m) + if sys.version_info[0] >= 3: + target = 'builtins.open' + else: + target = '__builtin__.open' + patcher = mock.patch(target, m) self.addCleanup(patcher.stop) patcher.start() @@ -77,7 +80,7 @@ class ConfigTestCase(unittest.TestCase): def clean_environment(self): self._config_files['system'] = '' self._config_files['user'] = '' - for k in os.environ.keys(): + for k in list(os.environ.keys()): if k.startswith(('UBUNTUTOOLS_', 'TEST_')): del os.environ[k] @@ -231,7 +234,11 @@ class UbuEmailTestCase(unittest.TestCase): encoding = locale.getdefaultlocale()[1] if not encoding: encoding = 'utf-8' - name = 'Jöe Déveloper'.decode('utf-8') - os.environ['DEBFULLNAME'] = name.encode(encoding) + name = 'Jöe Déveloper' + env_name = name + if isinstance(name, bytes): + name = 'Jöe Déveloper'.decode('utf-8') + env_name = name.encode(encoding) + os.environ['DEBFULLNAME'] = env_name os.environ['DEBEMAIL'] = email = 'joe@example.net' self.assertEqual(ubu_email(), (name, email)) From 412afabc1c6ef06eb2fc56d72f00aa5c4f573205 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 21:54:52 +0000 Subject: [PATCH 28/35] Fix maintainer --- ubuntutools/test/test_update_maintainer.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ubuntutools/test/test_update_maintainer.py b/ubuntutools/test/test_update_maintainer.py index e951ae5..798a28e 100644 --- a/ubuntutools/test/test_update_maintainer.py +++ b/ubuntutools/test/test_update_maintainer.py @@ -227,7 +227,11 @@ class UpdateMaintainerTestCase(unittest.TestCase): self.assertRegex = self.assertRegexpMatches m = mock.mock_open() m.side_effect = self._fake_open - patcher = mock.patch('__builtin__.open', m) + if sys.version_info[0] >= 3: + target = 'builtins.open' + else: + target = '__builtin__.open' + patcher = mock.patch(target, m) self.addCleanup(patcher.stop) patcher.start() m = mock.MagicMock(side_effect=self._fake_isfile) From ed0cd2c1b54162e7fec494081e6a9f5c8506bd0e Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 22:05:55 +0000 Subject: [PATCH 29/35] file is gone in python3 --- ubuntutools/sponsor_patch/source_package.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ubuntutools/sponsor_patch/source_package.py b/ubuntutools/sponsor_patch/source_package.py index 69910ec..b9fa2a0 100644 --- a/ubuntutools/sponsor_patch/source_package.py +++ b/ubuntutools/sponsor_patch/source_package.py @@ -351,7 +351,7 @@ class SourcePackage(object): assert os.path.isfile(self._changes_file), "%s does not exist." % \ (self._changes_file) - changes = debian.deb822.Changes(file(self._changes_file)) + changes = debian.deb822.Changes(open(self._changes_file)) fixed_bugs = [] if "Launchpad-Bugs-Fixed" in changes: fixed_bugs = changes["Launchpad-Bugs-Fixed"].split(" ") @@ -393,7 +393,7 @@ class SourcePackage(object): # Check the changelog self._changelog = debian.changelog.Changelog() try: - self._changelog.parse_changelog(file("debian/changelog"), + self._changelog.parse_changelog(open("debian/changelog"), max_blocks=1, strict=True) except debian.changelog.ChangelogParseError as error: Logger.error("The changelog entry doesn't validate: %s", str(error)) From 5da114b070a0d15d8443d9b6538bd8971626bbe5 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 23:03:23 +0000 Subject: [PATCH 30/35] More consistent binary handling throughout. Don't mock open(..., "b") with str / StringIO. Silence source package pull, buffered/mocked output does not flush. Disable mirror tests on python3, stall/hang. --- ubuntutools/archive.py | 8 ++++---- ubuntutools/test/test_archive.py | 29 ++++++++++++++++++++++++----- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/ubuntutools/archive.py b/ubuntutools/archive.py index 314f3b4..15626d9 100644 --- a/ubuntutools/archive.py +++ b/ubuntutools/archive.py @@ -90,7 +90,7 @@ class Dsc(debian.deb822.Dsc): f = open(pathname, 'rb') while True: buf = f.read(hash_func.block_size) - if buf == '': + if buf == b'': break hash_func.update(buf) f.close() @@ -327,7 +327,7 @@ class SourcePackage(object): filename, parsed.hostname, size / 1024.0 / 1024) if parsed.scheme == 'file': - in_ = open(parsed.path, 'r') + in_ = open(parsed.path, 'rb') else: try: in_ = self.url_opener.open(url) @@ -340,10 +340,10 @@ class SourcePackage(object): with open(pathname, 'wb') as out: while True: block = in_.read(10240) - if block == '': + if block == b'': break downloaded += len(block) - out.write(block) + out.write(block) if not self.quiet: percent = downloaded * 100 // size bar = '=' * int(round(downloaded * bar_width / size)) diff --git a/ubuntutools/test/test_archive.py b/ubuntutools/test/test_archive.py index 17c2346..2682a5b 100644 --- a/ubuntutools/test/test_archive.py +++ b/ubuntutools/test/test_archive.py @@ -36,6 +36,7 @@ except ImportError: from urllib2 import HTTPError import debian.deb822 import httplib2 +import sys import mock import ubuntutools.archive @@ -73,10 +74,18 @@ class DscVerificationTestCase(unittest.TestCase): fn = 'test-data/example_1.0.orig.tar.gz' with open(fn, 'rb') as f: data = f.read() - data = data[:-1] + chr(ord(data[-1]) ^ 8) + if sys.version_info[0] >= 3: + last_byte = chr(data[-1] ^ 8).encode() + else: + last_byte = chr(ord(data[-1]) ^ 8) + data = data[:-1] + last_byte m = mock.MagicMock(name='open', spec=open) m.return_value = BytesIO(data) - with mock.patch('__builtin__.open', m): + if sys.version_info[0] >= 3: + target = 'builtins.open' + else: + target = '__builtin__.open' + with mock.patch(target, m): self.assertFalse(self.dsc.verify_file(fn)) def test_sha1(self): @@ -131,7 +140,7 @@ class LocalSourcePackageTestCase(unittest.TestCase): def urlopen_null(self, url): "urlopen for zero length files" - return StringIO('') + return BytesIO(b'') def urlopen_404(self, url): "urlopen for errors" @@ -143,7 +152,7 @@ class LocalSourcePackageTestCase(unittest.TestCase): destname = os.path.basename(url) destpath = os.path.join(os.path.abspath('test-data'), destname) response = httplib2.Response({}) - with open(destpath, 'r') as f: + with open(destpath, 'rb') as f: body = f.read() return response, body @@ -162,6 +171,7 @@ class LocalSourcePackageTestCase(unittest.TestCase): pkg = self.SourcePackage('example', '1.0-1', 'main', dscfile='test-data/example_1.0-1.dsc', workdir=self.workdir) + pkg.quiet = True pkg.pull() pkg.unpack() @@ -173,6 +183,7 @@ class LocalSourcePackageTestCase(unittest.TestCase): pkg = self.SourcePackage(dscfile=os.path.join(self.workdir, 'example_1.0-1.dsc'), workdir=self.workdir) + pkg.quiet = True pkg.pull() pkg.unpack() @@ -185,6 +196,7 @@ class LocalSourcePackageTestCase(unittest.TestCase): dscfile=os.path.join(self.workdir, 'example_1.0-1.dsc'), workdir=self.workdir) + pkg.quiet = True pkg.pull() pkg.unpack() @@ -194,11 +206,12 @@ class LocalSourcePackageTestCase(unittest.TestCase): shutil.copy2('test-data/example_1.0-1.debian.tar.xz', self.workdir) with open(os.path.join(self.workdir, 'example_1.0-1.debian.tar.xz'), 'r+b') as f: - f.write('CORRUPTION') + f.write(b'CORRUPTION') pkg = self.SourcePackage('example', '1.0-1', 'main', dscfile='test-data/example_1.0-1.dsc', workdir=self.workdir) + pkg.quiet = True pkg.pull() def test_pull(self): @@ -210,8 +223,10 @@ class LocalSourcePackageTestCase(unittest.TestCase): workdir=self.workdir) pkg.url_opener = self.url_opener + pkg.quiet = True pkg.pull() + @unittest.skipIf(sys.version_info[0] >=3, "Stalls on PY3") def test_mirrors(self): master = UDTConfig.defaults['UBUNTU_MIRROR'] mirror = 'http://mirror' @@ -227,18 +242,21 @@ class LocalSourcePackageTestCase(unittest.TestCase): pkg = self.SourcePackage('example', '1.0-1', 'main', workdir=self.workdir, mirrors=[mirror]) pkg.url_opener = url_opener + pkg.quiet = True pkg.pull() def test_dsc_missing(self): self.mock_http.side_effect = self.request_404 pkg = self.SourcePackage('example', '1.0-1', 'main', workdir=self.workdir) + pkg.quiet = True self.assertRaises(ubuntutools.archive.DownloadError, pkg.pull) class DebianLocalSourcePackageTestCase(LocalSourcePackageTestCase): SourcePackage = ubuntutools.archive.DebianSourcePackage + @unittest.skipIf(sys.version_info[0] >=3, "Stalls on PY3") def test_mirrors(self): debian_master = UDTConfig.defaults['DEBIAN_MIRROR'] debsec_master = UDTConfig.defaults['DEBSEC_MIRROR'] @@ -264,6 +282,7 @@ class DebianLocalSourcePackageTestCase(LocalSourcePackageTestCase): pkg = self.SourcePackage('example', '1.0-1', 'main', workdir=self.workdir, mirrors=[debian_mirror, debsec_mirror]) + pkg.quiet = True pkg.url_opener = url_opener pkg.pull() pkg.unpack() From 866adfd768e7751a96d9853c505c7fb8462f7d14 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 23:18:00 +0000 Subject: [PATCH 31/35] Actually, now that more things expect streaming bytes over the wire the mirror tests don't stall anymore. Also use a codec.reader to slurp up unicode bytes for json.load. --- ubuntutools/archive.py | 8 ++++++-- ubuntutools/test/test_archive.py | 4 +--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ubuntutools/archive.py b/ubuntutools/archive.py index 15626d9..46d4c51 100644 --- a/ubuntutools/archive.py +++ b/ubuntutools/archive.py @@ -48,6 +48,7 @@ if sys.version_info[0] >= 3: from debian.changelog import Changelog, Version import debian.deb822 import debian.debian_support +import codecs import httplib2 from ubuntutools.config import UDTConfig @@ -508,10 +509,13 @@ class DebianSourcePackage(SourcePackage): "python-simplejson") try: - srcfiles = json.load(self.url_opener.open( + data = self.url_opener.open( 'http://snapshot.debian.org' '/mr/package/%s/%s/srcfiles?fileinfo=1' - % (self.source, self.version.full_version))) + % (self.source, self.version.full_version)) + reader = codecs.getreader('utf-8') + srcfiles = json.load(reader(data)) + except HTTPError: Logger.error('Version %s of %s not found on ' 'snapshot.debian.org', diff --git a/ubuntutools/test/test_archive.py b/ubuntutools/test/test_archive.py index 2682a5b..0593f40 100644 --- a/ubuntutools/test/test_archive.py +++ b/ubuntutools/test/test_archive.py @@ -226,7 +226,6 @@ class LocalSourcePackageTestCase(unittest.TestCase): pkg.quiet = True pkg.pull() - @unittest.skipIf(sys.version_info[0] >=3, "Stalls on PY3") def test_mirrors(self): master = UDTConfig.defaults['UBUNTU_MIRROR'] mirror = 'http://mirror' @@ -256,7 +255,6 @@ class LocalSourcePackageTestCase(unittest.TestCase): class DebianLocalSourcePackageTestCase(LocalSourcePackageTestCase): SourcePackage = ubuntutools.archive.DebianSourcePackage - @unittest.skipIf(sys.version_info[0] >=3, "Stalls on PY3") def test_mirrors(self): debian_master = UDTConfig.defaults['DEBIAN_MIRROR'] debsec_master = UDTConfig.defaults['DEBSEC_MIRROR'] @@ -271,7 +269,7 @@ class DebianLocalSourcePackageTestCase(LocalSourcePackageTestCase): self.urlopen_404, self.urlopen_404, lambda x: BytesIO( - '{"fileinfo": {"hashabc": [{"name": "example_1.0.orig.tar.gz"}]}}'), + b'{"fileinfo": {"hashabc": [{"name": "example_1.0.orig.tar.gz"}]}}'), self.urlopen_file('example_1.0.orig.tar.gz'), self.urlopen_proxy] def _callable_iter(*args, **kwargs): From 8ae64c16e20288b293edf80c1715a403709cf2be Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 23:35:00 +0000 Subject: [PATCH 32/35] Disable test_dsc_badsig, when no networking is available. --- ubuntutools/test/test_archive.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ubuntutools/test/test_archive.py b/ubuntutools/test/test_archive.py index 0593f40..4a7314e 100644 --- a/ubuntutools/test/test_archive.py +++ b/ubuntutools/test/test_archive.py @@ -30,10 +30,10 @@ import tempfile import types try: from urllib.request import OpenerDirector, urlopen - from urllib.error import HTTPError + from urllib.error import HTTPError, URLError except ImportError: from urllib2 import OpenerDirector, urlopen - from urllib2 import HTTPError + from urllib2 import HTTPError, URLError import debian.deb822 import httplib2 import sys @@ -317,4 +317,7 @@ class DebianLocalSourcePackageTestCase(LocalSourcePackageTestCase): pkg = self.SourcePackage('example', '1.0-1', 'main', workdir=self.workdir, mirrors=[mirror]) - self.assertRaises(ubuntutools.archive.DownloadError, pkg.pull) + try: + self.assertRaises(ubuntutools.archive.DownloadError, pkg.pull) + except URLError: + raise unittest.SkipTest('Test needs addr resolution to work') From e162e7d580ee08f2286c7468018e9a727e5fe3c4 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Dec 2014 23:51:59 +0000 Subject: [PATCH 33/35] Port ubuntutools library --- debian/control | 32 +++++++++++++++++++++++++++++++- debian/rules | 19 ++++++++++--------- setup.py | 20 +++++++++++++------- 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/debian/control b/debian/control index e5249b8..b915eec 100644 --- a/debian/control +++ b/debian/control @@ -8,6 +8,7 @@ Vcs-Bzr: lp:ubuntu-dev-tools Vcs-Browser: https://code.launchpad.net/~ubuntu-dev/ubuntu-dev-tools/trunk Build-Depends: dctrl-tools, debhelper (>= 9), + dh-python, devscripts (>= 2.11.0~), distro-info (>= 0.2~), libwww-perl, @@ -21,8 +22,17 @@ Build-Depends: dctrl-tools, python-launchpadlib (>= 1.5.7), python-setuptools, python-soappy, - python-unittest2 + python-unittest2, + python3-all, + python3-apt, + python3-debian, + python3-distro-info, + python3-httplib2, + python3-launchpadlib, + python3-setuptools, + python3-soappy, X-Python-Version: >= 2.6 +X-Python3-Version: >= 3.2 Homepage: https://launchpad.net/ubuntu-dev-tools Standards-Version: 3.9.5 @@ -113,3 +123,23 @@ Description: useful tools for Ubuntu developers - ubuntu-upload-permission - query / list the upload permissions for a package. - update-maintainer - script to update maintainer field in ubuntu packages. + +Package: python-ubuntutools +Architecture: all +Depends: ${python:Depends} +Breaks: ubuntu-dev-tools (<< 0.154) +Replaces: ubuntu-dev-tools (<< 0.154) +Description: useful library of APIs for Ubuntu developer tools (Python 2) + This package ships a collection of APIs, helpers and wrappers used to + develop useful utiliteis for Ubuntu developers. + . + Python 2 variant. + +Package: python3-ubuntutools +Architecture: all +Depends: ${python3:Depends} +Description: useful library of APIs for Ubuntu developer tools + This package ships a collection of APIs, helpers and wrappers used to + develop useful utiliteis for Ubuntu developers. + . + Python 3 variant. diff --git a/debian/rules b/debian/rules index da314d6..9baf9c1 100755 --- a/debian/rules +++ b/debian/rules @@ -1,12 +1,13 @@ #!/usr/bin/make -f -%: - dh $@ --with python2 +export PYBUILD_NAME=ubuntutools -ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) -override_dh_auto_test: - set -e; \ - for python in $(shell pyversions -r); do \ - $$python setup.py test; \ - done -endif +%: + dh $@ --with python2,python3 --buildsystem=pybuild + +override_dh_install: + dh_install + mkdir -p debian/ubuntu-dev-tools/usr + mv debian/python-ubuntutools/etc debian/ubuntu-dev-tools + mv debian/python-ubuntutools/usr/bin debian/ubuntu-dev-tools/usr/ + mv debian/python-ubuntutools/usr/share debian/ubuntu-dev-tools/usr/ diff --git a/setup.py b/setup.py index 8b0163f..b7f55e3 100755 --- a/setup.py +++ b/setup.py @@ -4,6 +4,7 @@ from setuptools import setup import glob import os import re +import sys # look/set what version we have changelog = "debian/changelog" @@ -13,7 +14,11 @@ if os.path.exists(changelog): if match: version = match.group(1) -scripts = ['404main', +if sys.version_info[0] >= 3: + scripts = [] + data_files = [] +else: + scripts = ['404main', 'backportpackage', 'bitesize', 'check-mir', @@ -46,6 +51,12 @@ scripts = ['404main', 'ubuntu-upload-permission', 'update-maintainer', ] + data_files = [ + ('/etc/bash_completion.d', glob.glob("bash_completion/*")), + ('share/man/man1', glob.glob("doc/*.1")), + ('share/man/man5', glob.glob("doc/*.5")), + ('share/ubuntu-dev-tools', ['enforced-editing-wrapper']), + ] if __name__ == '__main__': setup(name='ubuntu-dev-tools', @@ -57,11 +68,6 @@ if __name__ == '__main__': 'ubuntutools/sponsor_patch', 'ubuntutools/test', ], - data_files=[('/etc/bash_completion.d', - glob.glob("bash_completion/*")), - ('share/man/man1', glob.glob("doc/*.1")), - ('share/man/man5', glob.glob("doc/*.5")), - ('share/ubuntu-dev-tools', ['enforced-editing-wrapper']), - ], + data_files=data_files, test_suite='ubuntutools.test.discover', ) From 124e421b61d8a6c919c5d76c606f9b9dd1c21177 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Fri, 19 Dec 2014 22:42:46 +0000 Subject: [PATCH 34/35] There is no python3-soappy yet. --- debian/control | 1 - 1 file changed, 1 deletion(-) diff --git a/debian/control b/debian/control index b915eec..5c1de61 100644 --- a/debian/control +++ b/debian/control @@ -30,7 +30,6 @@ Build-Depends: dctrl-tools, python3-httplib2, python3-launchpadlib, python3-setuptools, - python3-soappy, X-Python-Version: >= 2.6 X-Python3-Version: >= 3.2 Homepage: https://launchpad.net/ubuntu-dev-tools From 149182a3cdd14dfe7e9d0bbafc97a2eba5a62fd5 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Fri, 19 Dec 2014 22:54:18 +0000 Subject: [PATCH 35/35] Mock mock more. --- debian/control | 2 ++ 1 file changed, 2 insertions(+) diff --git a/debian/control b/debian/control index 5c1de61..7e210e0 100644 --- a/debian/control +++ b/debian/control @@ -23,6 +23,7 @@ Build-Depends: dctrl-tools, python-setuptools, python-soappy, python-unittest2, + python-mock, python3-all, python3-apt, python3-debian, @@ -30,6 +31,7 @@ Build-Depends: dctrl-tools, python3-httplib2, python3-launchpadlib, python3-setuptools, + python3-mock, X-Python-Version: >= 2.6 X-Python3-Version: >= 3.2 Homepage: https://launchpad.net/ubuntu-dev-tools