Merge ~raharper/cloud-init:cloud-test-add-pylint-and-fix into cloud-init:master

Proposed by Ryan Harper
Status: Merged
Merged at revision: a110e483e8644ab73e69853ea11b6c4c6cfa04b6
Proposed branch: ~raharper/cloud-init:cloud-test-add-pylint-and-fix
Merge into: cloud-init:master
Diff against target: 884 lines (+121/-266)
29 files modified
.pylintrc (+1/-1)
cloudinit/cmd/tests/test_clean.py (+1/-1)
cloudinit/cmd/tests/test_status.py (+1/-1)
cloudinit/tests/helpers.py (+35/-0)
dev/null (+0/-172)
tests/cloud_tests/__init__.py (+6/-0)
tests/cloud_tests/bddeb.py (+4/-5)
tests/cloud_tests/collect.py (+3/-3)
tests/cloud_tests/config.py (+3/-1)
tests/cloud_tests/testcases/base.py (+2/-1)
tests/cloud_tests/testcases/modules/set_hostname_fqdn.py (+1/-1)
tests/cloud_tests/util.py (+1/-1)
tests/unittests/test_cs_util.py (+1/-0)
tests/unittests/test_datasource/test_azure.py (+14/-17)
tests/unittests/test_datasource/test_digitalocean.py (+6/-3)
tests/unittests/test_datasource/test_ec2.py (+2/-1)
tests/unittests/test_distros/test_create_users.py (+5/-2)
tests/unittests/test_distros/test_netconfig.py (+0/-3)
tests/unittests/test_handler/test_handler_lxd.py (+0/-3)
tests/unittests/test_handler/test_handler_power_state.py (+0/-3)
tests/unittests/test_handler/test_handler_yum_add_repo.py (+2/-8)
tests/unittests/test_handler/test_handler_zypper_add_repo.py (+1/-6)
tests/unittests/test_reporting.py (+1/-1)
tests/unittests/test_templating.py (+1/-1)
tests/unittests/test_util.py (+3/-3)
tests/unittests/test_vmware_config_file.py (+2/-1)
tools/make-mime.py (+1/-1)
tools/mock-meta.py (+21/-24)
tox.ini (+3/-2)
Reviewer Review Type Date Requested Status
Scott Moser Approve
Server Team CI bot continuous-integration Approve
Joshua Powers (community) Needs Fixing
Review via email: mp+334868@code.launchpad.net

Description of the change

pylint: Update pylint to 1.7.1, run on tests/ and fix complaints.

- Update tox.ini to invoke pylint v1.7.1.
- Modify .pylintrc generated-members ignore mocked object members (m_.*)
- Replace "dangerous" params defaulting to {}
- Fix up cloud_tests use of platforms
- Cast some instance objects to with dict()
- Handle python2.7 vs 3+ ConfigParser use of readfp (deprecated)
- Update use of assertEqual(<boolean>, value) to assert<Boolean>(value)
- replace depricated assertRegexp -> assertRegex
- Remove useless test-class calls to super class
- Assign class property accessors a result and use it
- Fix missing class member in CepkoResultTests
- Fix Cheetah test import

To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:5335e1632ddabdbad9ffb011720929ae4cd8ebe3
https://jenkins.ubuntu.com/server/job/cloud-init-ci/589/
Executed test runs:
    SUCCESS: Checkout
    FAILED: Unit & Style Tests

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/589/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Joshua Powers (powersj) wrote :

Thanks for doing this! Can you add comment to description/commit message about meta-data getting added to the integration tests?

Looks like a few tip-pylint errors, one of which is why I asked about getting rid of tools/hacking.py.

Otherwise I ran a full lxd and nocloud-kvm test run with no failures:
lxd: https://paste.ubuntu.com/26128706/
nocloud-kvm: https://paste.ubuntu.com/26128704/

review: Needs Fixing
Revision history for this message
Ryan Harper (raharper) wrote :

Didn't mean to run on tools for now.

w.r.t the meta-data bits, I'll defer to Scott, he did that first bit.

On Wed, Dec 6, 2017 at 5:15 PM, Joshua Powers <email address hidden>
wrote:

> Review: Needs Fixing
>
> Thanks for doing this! Can you add comment to description/commit message
> about meta-data getting added to the integration tests?
>
> Looks like a few tip-pylint errors, one of which is why I asked about
> getting rid of tools/hacking.py.
>
> Otherwise I ran a full lxd and nocloud-kvm test run with no failures:
> lxd: https://paste.ubuntu.com/26128706/
> nocloud-kvm: https://paste.ubuntu.com/26128704/
>
>
> --
> https://code.launchpad.net/~raharper/cloud-init/+git/
> cloud-init/+merge/334868
> You are the owner of ~raharper/cloud-init:cloud-test-add-pylint-and-fix.
>

Revision history for this message
Scott Moser (smoser) wrote :

assuming c-i is happy with this, then i am too.
please do mention tools/hacking.py removal in your commit message.
it is obsolete now as we use 'hacking' module in tox.ini for flake8

Revision history for this message
Scott Moser (smoser) :
review: Approve
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:ca2ce2ecb149ab6b36ec525d234f513c676210d1
https://jenkins.ubuntu.com/server/job/cloud-init-ci/597/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    FAILED: MAAS Compatability Testing

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/597/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:abb799ecc8827ac1f84012234e53fb002b70bab4
https://jenkins.ubuntu.com/server/job/cloud-init-ci/598/
Executed test runs:
    SUCCESS: Checkout
    FAILED: Unit & Style Tests

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/598/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:d265c4416eda1345cd1bca6c0784226aa1d2472e
https://jenkins.ubuntu.com/server/job/cloud-init-ci/599/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    SUCCESS: MAAS Compatability Testing
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/599/rebuild

review: Approve (continuous-integration)
Revision history for this message
Scott Moser (smoser) wrote :

locally i've been through this locally
 tox && ./tools/run-centos 6 --rpm --srpm --unittest &&
   ./tools/run-centos 7 --rpm --srpm --unittest

And c-i is just about to agree
 https://jenkins.ubuntu.com/server/job/cloud-init-ci/599/console

I am making one change though. i'm going to move the '_tricky' bit for assertRaisesRegex back to the bottom of the file. it seems to fit better there with the other bits that are already there. (and i've tested the above).

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/.pylintrc b/.pylintrc
index b160ce7..3ad3692 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -56,5 +56,5 @@ ignored-classes=optparse.Values,thread._local
56# List of members which are set dynamically and missed by pylint inference56# List of members which are set dynamically and missed by pylint inference
57# system, and so shouldn't trigger E1101 when accessed. Python regular57# system, and so shouldn't trigger E1101 when accessed. Python regular
58# expressions are accepted.58# expressions are accepted.
59generated-members=types,http.client,command_handlers59generated-members=types,http.client,command_handlers,m_.*
6060
diff --git a/cloudinit/cmd/tests/test_clean.py b/cloudinit/cmd/tests/test_clean.py
index af438aa..1379740 100644
--- a/cloudinit/cmd/tests/test_clean.py
+++ b/cloudinit/cmd/tests/test_clean.py
@@ -151,7 +151,7 @@ class TestClean(CiTestCase):
151 'sys.argv': {'new': ['clean', '--logs']}},151 'sys.argv': {'new': ['clean', '--logs']}},
152 clean.main)152 clean.main)
153153
154 self.assertEqual(0, context_manager.exception.code)154 self.assertRaisesCodeEqual(0, context_manager.exception.code)
155 self.assertFalse(155 self.assertFalse(
156 os.path.exists(self.log1), 'Unexpected log {0}'.format(self.log1))156 os.path.exists(self.log1), 'Unexpected log {0}'.format(self.log1))
157157
diff --git a/cloudinit/cmd/tests/test_status.py b/cloudinit/cmd/tests/test_status.py
index 8ec9b5b..6d4a11e 100644
--- a/cloudinit/cmd/tests/test_status.py
+++ b/cloudinit/cmd/tests/test_status.py
@@ -347,7 +347,7 @@ class TestStatus(CiTestCase):
347 '_is_cloudinit_disabled': (False, ''),347 '_is_cloudinit_disabled': (False, ''),
348 'Init': {'side_effect': self.init_class}},348 'Init': {'side_effect': self.init_class}},
349 status.main)349 status.main)
350 self.assertEqual(0, context_manager.exception.code)350 self.assertRaisesCodeEqual(0, context_manager.exception.code)
351 self.assertEqual('status: running\n', m_stdout.getvalue())351 self.assertEqual('status: running\n', m_stdout.getvalue())
352352
353# vi: ts=4 expandtab syntax=python353# vi: ts=4 expandtab syntax=python
diff --git a/cloudinit/tests/helpers.py b/cloudinit/tests/helpers.py
index feb884a..f3dc779 100644
--- a/cloudinit/tests/helpers.py
+++ b/cloudinit/tests/helpers.py
@@ -19,9 +19,22 @@ try:
19except ImportError:19except ImportError:
20 from contextlib2 import ExitStack20 from contextlib2 import ExitStack
2121
22try:
23 from configparser import ConfigParser
24except ImportError:
25 from ConfigParser import ConfigParser
26
22from cloudinit import helpers as ch27from cloudinit import helpers as ch
23from cloudinit import util28from cloudinit import util
2429
30# older unittest2.TestCase (centos6) do not have assertRaisesRegex
31# And setting assertRaisesRegex to assertRaisesRegexp causes
32# https://github.com/PyCQA/pylint/issues/1653 . So the workaround.
33if not hasattr(unittest2.TestCase, 'assertRaisesRegex'):
34 def _tricky(*args, **kwargs):
35 return unittest2.TestCase.assertRaisesRegexp
36 unittest2.TestCase.assertRaisesRegex = _tricky
37
25# Used for skipping tests38# Used for skipping tests
26SkipTest = unittest2.SkipTest39SkipTest = unittest2.SkipTest
2740
@@ -113,6 +126,16 @@ class TestCase(unittest2.TestCase):
113 self.addCleanup(m.stop)126 self.addCleanup(m.stop)
114 setattr(self, attr, p)127 setattr(self, attr, p)
115128
129 # prefer python3 read_file over readfp but allow fallback
130 def parse_and_read(self, contents):
131 parser = ConfigParser()
132 if hasattr(parser, 'read_file'):
133 parser.read_file(contents)
134 elif hasattr(parser, 'readfp'):
135 # pylint: disable=W1505
136 parser.readfp(contents)
137 return parser
138
116139
117class CiTestCase(TestCase):140class CiTestCase(TestCase):
118 """This is the preferred test case base class unless user141 """This is the preferred test case base class unless user
@@ -158,6 +181,18 @@ class CiTestCase(TestCase):
158 dir = self.tmp_dir()181 dir = self.tmp_dir()
159 return os.path.normpath(os.path.abspath(os.path.join(dir, path)))182 return os.path.normpath(os.path.abspath(os.path.join(dir, path)))
160183
184 def assertRaisesCodeEqual(self, expected, found):
185 """Handle centos6 having different context manager for assertRaises.
186 with assertRaises(Exception) as e:
187 raise Exception("BOO")
188
189 centos6 will have e.exception as an integer.
190 anything nwere will have it as something with a '.code'"""
191 if isinstance(found, int):
192 self.assertEqual(expected, found)
193 else:
194 self.assertEqual(expected, found.code)
195
161196
162class ResourceUsingTestCase(CiTestCase):197class ResourceUsingTestCase(CiTestCase):
163198
diff --git a/tests/cloud_tests/__init__.py b/tests/cloud_tests/__init__.py
index 98c1d6c..dd43698 100644
--- a/tests/cloud_tests/__init__.py
+++ b/tests/cloud_tests/__init__.py
@@ -10,6 +10,12 @@ TESTCASES_DIR = os.path.join(BASE_DIR, 'testcases')
10TEST_CONF_DIR = os.path.join(BASE_DIR, 'testcases')10TEST_CONF_DIR = os.path.join(BASE_DIR, 'testcases')
11TREE_BASE = os.sep.join(BASE_DIR.split(os.sep)[:-2])11TREE_BASE = os.sep.join(BASE_DIR.split(os.sep)[:-2])
1212
13# This domain contains reverse lookups for hostnames that are used.
14# The primary reason is so sudo will return quickly when it attempts
15# to look up the hostname. i9n is just short for 'integration'.
16# see also bug 1730744 for why we had to do this.
17CI_DOMAIN = "i9n.cloud-init.io"
18
1319
14def _initialize_logging():20def _initialize_logging():
15 """Configure logging for cloud_tests."""21 """Configure logging for cloud_tests."""
diff --git a/tests/cloud_tests/bddeb.py b/tests/cloud_tests/bddeb.py
index c259dfe..a6d5069 100644
--- a/tests/cloud_tests/bddeb.py
+++ b/tests/cloud_tests/bddeb.py
@@ -8,8 +8,7 @@ import tempfile
88
9from cloudinit import util as c_util9from cloudinit import util as c_util
10from tests.cloud_tests import (config, LOG)10from tests.cloud_tests import (config, LOG)
11from tests.cloud_tests.platforms import (platforms, images, snapshots,11from tests.cloud_tests import platforms
12 instances)
13from tests.cloud_tests.stage import (PlatformComponent, run_stage, run_single)12from tests.cloud_tests.stage import (PlatformComponent, run_stage, run_single)
1413
15pre_reqs = ['devscripts', 'equivs', 'git', 'tar']14pre_reqs = ['devscripts', 'equivs', 'git', 'tar']
@@ -85,18 +84,18 @@ def setup_build(args):
85 # set up image84 # set up image
86 LOG.info('acquiring image for os: %s', args.build_os)85 LOG.info('acquiring image for os: %s', args.build_os)
87 img_conf = config.load_os_config(platform.platform_name, args.build_os)86 img_conf = config.load_os_config(platform.platform_name, args.build_os)
88 image_call = partial(images.get_image, platform, img_conf)87 image_call = partial(platforms.get_image, platform, img_conf)
89 with PlatformComponent(image_call) as image:88 with PlatformComponent(image_call) as image:
9089
91 # set up snapshot90 # set up snapshot
92 snapshot_call = partial(snapshots.get_snapshot, image)91 snapshot_call = partial(platforms.get_snapshot, image)
93 with PlatformComponent(snapshot_call) as snapshot:92 with PlatformComponent(snapshot_call) as snapshot:
9493
95 # create instance with cloud-config to set it up94 # create instance with cloud-config to set it up
96 LOG.info('creating instance to build deb in')95 LOG.info('creating instance to build deb in')
97 empty_cloud_config = "#cloud-config\n{}"96 empty_cloud_config = "#cloud-config\n{}"
98 instance_call = partial(97 instance_call = partial(
99 instances.get_instance, snapshot, empty_cloud_config,98 platforms.get_instance, snapshot, empty_cloud_config,
100 use_desc='build cloud-init deb')99 use_desc='build cloud-init deb')
101 with PlatformComponent(instance_call) as instance:100 with PlatformComponent(instance_call) as instance:
102101
diff --git a/tests/cloud_tests/collect.py b/tests/cloud_tests/collect.py
index db5ee99..4805cea 100644
--- a/tests/cloud_tests/collect.py
+++ b/tests/cloud_tests/collect.py
@@ -64,9 +64,9 @@ def collect_test_data(args, snapshot, os_name, test_name):
64 # skip the testcase with a warning64 # skip the testcase with a warning
65 req_features = test_config.get('required_features', [])65 req_features = test_config.get('required_features', [])
66 if any(feature not in snapshot.features for feature in req_features):66 if any(feature not in snapshot.features for feature in req_features):
67 LOG.warn('test config %s requires features not supported by image, '67 LOG.warning('test config %s requires features not supported by image, '
68 'skipping.\nrequired features: %s\nsupported features: %s',68 'skipping.\nrequired features: %s\nsupported features: %s',
69 test_name, req_features, snapshot.features)69 test_name, req_features, snapshot.features)
70 return ({}, 0)70 return ({}, 0)
7171
72 # if there are user data overrides required for this test case, apply them72 # if there are user data overrides required for this test case, apply them
diff --git a/tests/cloud_tests/config.py b/tests/cloud_tests/config.py
index 52fc2bd..8bd569f 100644
--- a/tests/cloud_tests/config.py
+++ b/tests/cloud_tests/config.py
@@ -92,7 +92,7 @@ def load_platform_config(platform_name, require_enabled=False):
9292
9393
94def load_os_config(platform_name, os_name, require_enabled=False,94def load_os_config(platform_name, os_name, require_enabled=False,
95 feature_overrides={}):95 feature_overrides=None):
96 """Load configuration for os.96 """Load configuration for os.
9797
98 @param platform_name: platform name to load os config for98 @param platform_name: platform name to load os config for
@@ -101,6 +101,8 @@ def load_os_config(platform_name, os_name, require_enabled=False,
101 @param feature_overrides: feature flag overrides to merge with features101 @param feature_overrides: feature flag overrides to merge with features
102 @return_value: config dict102 @return_value: config dict
103 """103 """
104 if feature_overrides is None:
105 feature_overrides = {}
104 main_conf = c_util.read_conf(RELEASES_CONF)106 main_conf = c_util.read_conf(RELEASES_CONF)
105 default = main_conf['default_release_config']107 default = main_conf['default_release_config']
106 image = main_conf['releases'][os_name]108 image = main_conf['releases'][os_name]
diff --git a/tests/cloud_tests/testcases/base.py b/tests/cloud_tests/testcases/base.py
index 1706f59..1c5b540 100644
--- a/tests/cloud_tests/testcases/base.py
+++ b/tests/cloud_tests/testcases/base.py
@@ -12,7 +12,8 @@ from cloudinit import util as c_util
12class CloudTestCase(unittest.TestCase):12class CloudTestCase(unittest.TestCase):
13 """Base test class for verifiers."""13 """Base test class for verifiers."""
1414
15 data = None15 # data gets populated in get_suite.setUpClass
16 data = {}
16 conf = None17 conf = None
17 _cloud_config = None18 _cloud_config = None
1819
diff --git a/tests/cloud_tests/testcases/modules/set_hostname_fqdn.py b/tests/cloud_tests/testcases/modules/set_hostname_fqdn.py
index eb6f065..a405b30 100644
--- a/tests/cloud_tests/testcases/modules/set_hostname_fqdn.py
+++ b/tests/cloud_tests/testcases/modules/set_hostname_fqdn.py
@@ -1,7 +1,7 @@
1# This file is part of cloud-init. See LICENSE file for license information.1# This file is part of cloud-init. See LICENSE file for license information.
22
3"""cloud-init Integration Test Verify Script."""3"""cloud-init Integration Test Verify Script."""
4from tests.cloud_tests.instances.nocloudkvm import CI_DOMAIN4from tests.cloud_tests import CI_DOMAIN
5from tests.cloud_tests.testcases import base5from tests.cloud_tests.testcases import base
66
77
diff --git a/tests/cloud_tests/util.py b/tests/cloud_tests/util.py
index c5cd697..2aedcd0 100644
--- a/tests/cloud_tests/util.py
+++ b/tests/cloud_tests/util.py
@@ -262,7 +262,7 @@ def shell_safe(cmd):
262 out = subprocess.check_output(262 out = subprocess.check_output(
263 ["getopt", "--shell", "sh", "--options", "", "--", "--"] + list(cmd))263 ["getopt", "--shell", "sh", "--options", "", "--", "--"] + list(cmd))
264 # out contains ' -- <data>\n'. drop the ' -- ' and the '\n'264 # out contains ' -- <data>\n'. drop the ' -- ' and the '\n'
265 return out[4:-1].decode()265 return out.decode()[4:-1]
266266
267267
268def shell_pack(cmd):268def shell_pack(cmd):
diff --git a/tests/unittests/test_cs_util.py b/tests/unittests/test_cs_util.py
index ee88520..2a1095b 100644
--- a/tests/unittests/test_cs_util.py
+++ b/tests/unittests/test_cs_util.py
@@ -35,6 +35,7 @@ class CepkoMock(Cepko):
35# touched the underlying Cepko class methods.35# touched the underlying Cepko class methods.
36class CepkoResultTests(test_helpers.TestCase):36class CepkoResultTests(test_helpers.TestCase):
37 def setUp(self):37 def setUp(self):
38 self.c = Cepko()
38 raise test_helpers.SkipTest('This test is completely useless')39 raise test_helpers.SkipTest('This test is completely useless')
3940
40 def test_getitem(self):41 def test_getitem(self):
diff --git a/tests/unittests/test_datasource/test_azure.py b/tests/unittests/test_datasource/test_azure.py
index 226c214..5ab4889 100644
--- a/tests/unittests/test_datasource/test_azure.py
+++ b/tests/unittests/test_datasource/test_azure.py
@@ -36,9 +36,9 @@ def construct_valid_ovf_env(data=None, pubkeys=None, userdata=None):
36 """36 """
37 for key, dval in data.items():37 for key, dval in data.items():
38 if isinstance(dval, dict):38 if isinstance(dval, dict):
39 val = dval.get('text')39 val = dict(dval).get('text')
40 attrs = ' ' + ' '.join(["%s='%s'" % (k, v) for k, v in dval.items()40 attrs = ' ' + ' '.join(["%s='%s'" % (k, v) for k, v
41 if k != 'text'])41 in dict(dval).items() if k != 'text'])
42 else:42 else:
43 val = dval43 val = dval
44 attrs = ""44 attrs = ""
@@ -897,9 +897,6 @@ class TestCanDevBeReformatted(CiTestCase):
897 setattr(self, sattr, patcher.start())897 setattr(self, sattr, patcher.start())
898 self.addCleanup(patcher.stop)898 self.addCleanup(patcher.stop)
899899
900 def setUp(self):
901 super(TestCanDevBeReformatted, self).setUp()
902
903 def patchup(self, devs):900 def patchup(self, devs):
904 bypath = {}901 bypath = {}
905 for path, data in devs.items():902 for path, data in devs.items():
@@ -954,14 +951,14 @@ class TestCanDevBeReformatted(CiTestCase):
954 '/dev/sda3': {'num': 3},951 '/dev/sda3': {'num': 3},
955 }}})952 }}})
956 value, msg = dsaz.can_dev_be_reformatted("/dev/sda")953 value, msg = dsaz.can_dev_be_reformatted("/dev/sda")
957 self.assertFalse(False, value)954 self.assertFalse(value)
958 self.assertIn("3 or more", msg.lower())955 self.assertIn("3 or more", msg.lower())
959956
960 def test_no_partitions_is_false(self):957 def test_no_partitions_is_false(self):
961 """A disk with no partitions can not be formatted."""958 """A disk with no partitions can not be formatted."""
962 self.patchup({'/dev/sda': {}})959 self.patchup({'/dev/sda': {}})
963 value, msg = dsaz.can_dev_be_reformatted("/dev/sda")960 value, msg = dsaz.can_dev_be_reformatted("/dev/sda")
964 self.assertEqual(False, value)961 self.assertFalse(value)
965 self.assertIn("not partitioned", msg.lower())962 self.assertIn("not partitioned", msg.lower())
966963
967 def test_two_partitions_not_ntfs_false(self):964 def test_two_partitions_not_ntfs_false(self):
@@ -973,7 +970,7 @@ class TestCanDevBeReformatted(CiTestCase):
973 '/dev/sda2': {'num': 2, 'fs': 'ext4', 'files': []},970 '/dev/sda2': {'num': 2, 'fs': 'ext4', 'files': []},
974 }}})971 }}})
975 value, msg = dsaz.can_dev_be_reformatted("/dev/sda")972 value, msg = dsaz.can_dev_be_reformatted("/dev/sda")
976 self.assertFalse(False, value)973 self.assertFalse(value)
977 self.assertIn("not ntfs", msg.lower())974 self.assertIn("not ntfs", msg.lower())
978975
979 def test_two_partitions_ntfs_populated_false(self):976 def test_two_partitions_ntfs_populated_false(self):
@@ -986,7 +983,7 @@ class TestCanDevBeReformatted(CiTestCase):
986 'files': ['secret.txt']},983 'files': ['secret.txt']},
987 }}})984 }}})
988 value, msg = dsaz.can_dev_be_reformatted("/dev/sda")985 value, msg = dsaz.can_dev_be_reformatted("/dev/sda")
989 self.assertFalse(False, value)986 self.assertFalse(value)
990 self.assertIn("files on it", msg.lower())987 self.assertIn("files on it", msg.lower())
991988
992 def test_two_partitions_ntfs_empty_is_true(self):989 def test_two_partitions_ntfs_empty_is_true(self):
@@ -998,7 +995,7 @@ class TestCanDevBeReformatted(CiTestCase):
998 '/dev/sda2': {'num': 2, 'fs': 'ntfs', 'files': []},995 '/dev/sda2': {'num': 2, 'fs': 'ntfs', 'files': []},
999 }}})996 }}})
1000 value, msg = dsaz.can_dev_be_reformatted("/dev/sda")997 value, msg = dsaz.can_dev_be_reformatted("/dev/sda")
1001 self.assertEqual(True, value)998 self.assertTrue(value)
1002 self.assertIn("safe for", msg.lower())999 self.assertIn("safe for", msg.lower())
10031000
1004 def test_one_partition_not_ntfs_false(self):1001 def test_one_partition_not_ntfs_false(self):
@@ -1009,7 +1006,7 @@ class TestCanDevBeReformatted(CiTestCase):
1009 '/dev/sda1': {'num': 1, 'fs': 'zfs'},1006 '/dev/sda1': {'num': 1, 'fs': 'zfs'},
1010 }}})1007 }}})
1011 value, msg = dsaz.can_dev_be_reformatted("/dev/sda")1008 value, msg = dsaz.can_dev_be_reformatted("/dev/sda")
1012 self.assertEqual(False, value)1009 self.assertFalse(value)
1013 self.assertIn("not ntfs", msg.lower())1010 self.assertIn("not ntfs", msg.lower())
10141011
1015 def test_one_partition_ntfs_populated_false(self):1012 def test_one_partition_ntfs_populated_false(self):
@@ -1021,7 +1018,7 @@ class TestCanDevBeReformatted(CiTestCase):
1021 'files': ['file1.txt', 'file2.exe']},1018 'files': ['file1.txt', 'file2.exe']},
1022 }}})1019 }}})
1023 value, msg = dsaz.can_dev_be_reformatted("/dev/sda")1020 value, msg = dsaz.can_dev_be_reformatted("/dev/sda")
1024 self.assertEqual(False, value)1021 self.assertFalse(value)
1025 self.assertIn("files on it", msg.lower())1022 self.assertIn("files on it", msg.lower())
10261023
1027 def test_one_partition_ntfs_empty_is_true(self):1024 def test_one_partition_ntfs_empty_is_true(self):
@@ -1032,7 +1029,7 @@ class TestCanDevBeReformatted(CiTestCase):
1032 '/dev/sda1': {'num': 1, 'fs': 'ntfs', 'files': []}1029 '/dev/sda1': {'num': 1, 'fs': 'ntfs', 'files': []}
1033 }}})1030 }}})
1034 value, msg = dsaz.can_dev_be_reformatted("/dev/sda")1031 value, msg = dsaz.can_dev_be_reformatted("/dev/sda")
1035 self.assertEqual(True, value)1032 self.assertTrue(value)
1036 self.assertIn("safe for", msg.lower())1033 self.assertIn("safe for", msg.lower())
10371034
1038 def test_one_partition_ntfs_empty_with_dataloss_file_is_true(self):1035 def test_one_partition_ntfs_empty_with_dataloss_file_is_true(self):
@@ -1044,7 +1041,7 @@ class TestCanDevBeReformatted(CiTestCase):
1044 'files': ['dataloss_warning_readme.txt']}1041 'files': ['dataloss_warning_readme.txt']}
1045 }}})1042 }}})
1046 value, msg = dsaz.can_dev_be_reformatted("/dev/sda")1043 value, msg = dsaz.can_dev_be_reformatted("/dev/sda")
1047 self.assertEqual(True, value)1044 self.assertTrue(value)
1048 self.assertIn("safe for", msg.lower())1045 self.assertIn("safe for", msg.lower())
10491046
1050 def test_one_partition_through_realpath_is_true(self):1047 def test_one_partition_through_realpath_is_true(self):
@@ -1059,7 +1056,7 @@ class TestCanDevBeReformatted(CiTestCase):
1059 'realpath': '/dev/sdb1'}1056 'realpath': '/dev/sdb1'}
1060 }}})1057 }}})
1061 value, msg = dsaz.can_dev_be_reformatted(epath)1058 value, msg = dsaz.can_dev_be_reformatted(epath)
1062 self.assertEqual(True, value)1059 self.assertTrue(value)
1063 self.assertIn("safe for", msg.lower())1060 self.assertIn("safe for", msg.lower())
10641061
1065 def test_three_partition_through_realpath_is_false(self):1062 def test_three_partition_through_realpath_is_false(self):
@@ -1078,7 +1075,7 @@ class TestCanDevBeReformatted(CiTestCase):
1078 'realpath': '/dev/sdb3'}1075 'realpath': '/dev/sdb3'}
1079 }}})1076 }}})
1080 value, msg = dsaz.can_dev_be_reformatted(epath)1077 value, msg = dsaz.can_dev_be_reformatted(epath)
1081 self.assertEqual(False, value)1078 self.assertFalse(value)
1082 self.assertIn("3 or more", msg.lower())1079 self.assertIn("3 or more", msg.lower())
10831080
10841081
diff --git a/tests/unittests/test_datasource/test_digitalocean.py b/tests/unittests/test_datasource/test_digitalocean.py
index ec32173..3127014 100644
--- a/tests/unittests/test_datasource/test_digitalocean.py
+++ b/tests/unittests/test_datasource/test_digitalocean.py
@@ -199,9 +199,8 @@ class TestDataSourceDigitalOcean(CiTestCase):
199199
200class TestNetworkConvert(CiTestCase):200class TestNetworkConvert(CiTestCase):
201201
202 @mock.patch('cloudinit.net.get_interfaces_by_mac')202 def _get_networking(self):
203 def _get_networking(self, m_get_by_mac):203 self.m_get_by_mac.return_value = {
204 m_get_by_mac.return_value = {
205 '04:01:57:d1:9e:01': 'ens1',204 '04:01:57:d1:9e:01': 'ens1',
206 '04:01:57:d1:9e:02': 'ens2',205 '04:01:57:d1:9e:02': 'ens2',
207 'b8:ae:ed:75:5f:9a': 'enp0s25',206 'b8:ae:ed:75:5f:9a': 'enp0s25',
@@ -211,6 +210,10 @@ class TestNetworkConvert(CiTestCase):
211 self.assertIn('config', netcfg)210 self.assertIn('config', netcfg)
212 return netcfg211 return netcfg
213212
213 def setUp(self):
214 super(TestNetworkConvert, self).setUp()
215 self.add_patch('cloudinit.net.get_interfaces_by_mac', 'm_get_by_mac')
216
214 def test_networking_defined(self):217 def test_networking_defined(self):
215 netcfg = self._get_networking()218 netcfg = self._get_networking()
216 self.assertIsNotNone(netcfg)219 self.assertIsNotNone(netcfg)
diff --git a/tests/unittests/test_datasource/test_ec2.py b/tests/unittests/test_datasource/test_ec2.py
index ba042ea..f0dc833 100644
--- a/tests/unittests/test_datasource/test_ec2.py
+++ b/tests/unittests/test_datasource/test_ec2.py
@@ -330,7 +330,8 @@ class TestEc2(test_helpers.HttprettyTestCase):
330 ds.fallback_nic = 'eth9'330 ds.fallback_nic = 'eth9'
331 with mock.patch(get_interface_mac_path) as m_get_interface_mac:331 with mock.patch(get_interface_mac_path) as m_get_interface_mac:
332 m_get_interface_mac.return_value = mac1332 m_get_interface_mac.return_value = mac1
333 ds.network_config # Will re-crawl network metadata333 nc = ds.network_config # Will re-crawl network metadata
334 self.assertIsNotNone(nc)
334 self.assertIn('Re-crawl of metadata service', self.logs.getvalue())335 self.assertIn('Re-crawl of metadata service', self.logs.getvalue())
335 expected = {'version': 1, 'config': [336 expected = {'version': 1, 'config': [
336 {'mac_address': '06:17:04:d7:26:09',337 {'mac_address': '06:17:04:d7:26:09',
diff --git a/tests/unittests/test_distros/test_create_users.py b/tests/unittests/test_distros/test_create_users.py
index aa13670..5670904 100644
--- a/tests/unittests/test_distros/test_create_users.py
+++ b/tests/unittests/test_distros/test_create_users.py
@@ -7,7 +7,11 @@ from cloudinit.tests.helpers import (TestCase, mock)
7class MyBaseDistro(distros.Distro):7class MyBaseDistro(distros.Distro):
8 # MyBaseDistro is here to test base Distro class implementations8 # MyBaseDistro is here to test base Distro class implementations
99
10 def __init__(self, name="basedistro", cfg={}, paths={}):10 def __init__(self, name="basedistro", cfg=None, paths=None):
11 if not cfg:
12 cfg = {}
13 if not paths:
14 paths = {}
11 super(MyBaseDistro, self).__init__(name, cfg, paths)15 super(MyBaseDistro, self).__init__(name, cfg, paths)
1216
13 def install_packages(self, pkglist):17 def install_packages(self, pkglist):
@@ -42,7 +46,6 @@ class MyBaseDistro(distros.Distro):
42@mock.patch("cloudinit.distros.util.subp")46@mock.patch("cloudinit.distros.util.subp")
43class TestCreateUser(TestCase):47class TestCreateUser(TestCase):
44 def setUp(self):48 def setUp(self):
45 super(TestCase, self).setUp()
46 self.dist = MyBaseDistro()49 self.dist = MyBaseDistro()
4750
48 def _useradd2call(self, args):51 def _useradd2call(self, args):
diff --git a/tests/unittests/test_distros/test_netconfig.py b/tests/unittests/test_distros/test_netconfig.py
index c4bd11b..8d0b263 100644
--- a/tests/unittests/test_distros/test_netconfig.py
+++ b/tests/unittests/test_distros/test_netconfig.py
@@ -188,9 +188,6 @@ hn0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
188 status: active188 status: active
189"""189"""
190190
191 def setUp(self):
192 super(TestNetCfgDistro, self).setUp()
193
194 def _get_distro(self, dname, renderers=None):191 def _get_distro(self, dname, renderers=None):
195 cls = distros.fetch(dname)192 cls = distros.fetch(dname)
196 cfg = settings.CFG_BUILTIN193 cfg = settings.CFG_BUILTIN
diff --git a/tests/unittests/test_handler/test_handler_lxd.py b/tests/unittests/test_handler/test_handler_lxd.py
index e0d9ab6..a205498 100644
--- a/tests/unittests/test_handler/test_handler_lxd.py
+++ b/tests/unittests/test_handler/test_handler_lxd.py
@@ -25,9 +25,6 @@ class TestLxd(t_help.CiTestCase):
25 }25 }
26 }26 }
2727
28 def setUp(self):
29 super(TestLxd, self).setUp()
30
31 def _get_cloud(self, distro):28 def _get_cloud(self, distro):
32 cls = distros.fetch(distro)29 cls = distros.fetch(distro)
33 paths = helpers.Paths({})30 paths = helpers.Paths({})
diff --git a/tests/unittests/test_handler/test_handler_power_state.py b/tests/unittests/test_handler/test_handler_power_state.py
index 85a0fe0..3c72642 100644
--- a/tests/unittests/test_handler/test_handler_power_state.py
+++ b/tests/unittests/test_handler/test_handler_power_state.py
@@ -9,9 +9,6 @@ from cloudinit.tests.helpers import mock
99
1010
11class TestLoadPowerState(t_help.TestCase):11class TestLoadPowerState(t_help.TestCase):
12 def setUp(self):
13 super(self.__class__, self).setUp()
14
15 def test_no_config(self):12 def test_no_config(self):
16 # completely empty config should mean do nothing13 # completely empty config should mean do nothing
17 (cmd, _timeout, _condition) = psc.load_power_state({})14 (cmd, _timeout, _condition) = psc.load_power_state({})
diff --git a/tests/unittests/test_handler/test_handler_yum_add_repo.py b/tests/unittests/test_handler/test_handler_yum_add_repo.py
index b7adbe5..b90a3af 100644
--- a/tests/unittests/test_handler/test_handler_yum_add_repo.py
+++ b/tests/unittests/test_handler/test_handler_yum_add_repo.py
@@ -5,10 +5,6 @@ from cloudinit import util
55
6from cloudinit.tests import helpers6from cloudinit.tests import helpers
77
8try:
9 from configparser import ConfigParser
10except ImportError:
11 from ConfigParser import ConfigParser
12import logging8import logging
13import shutil9import shutil
14from six import StringIO10from six import StringIO
@@ -58,8 +54,7 @@ class TestConfig(helpers.FilesystemMockingTestCase):
58 self.patchUtils(self.tmp)54 self.patchUtils(self.tmp)
59 cc_yum_add_repo.handle('yum_add_repo', cfg, None, LOG, [])55 cc_yum_add_repo.handle('yum_add_repo', cfg, None, LOG, [])
60 contents = util.load_file("/etc/yum.repos.d/epel_testing.repo")56 contents = util.load_file("/etc/yum.repos.d/epel_testing.repo")
61 parser = ConfigParser()57 parser = self.parse_and_read(StringIO(contents))
62 parser.readfp(StringIO(contents))
63 expected = {58 expected = {
64 'epel_testing': {59 'epel_testing': {
65 'name': 'Extra Packages for Enterprise Linux 5 - Testing',60 'name': 'Extra Packages for Enterprise Linux 5 - Testing',
@@ -95,8 +90,7 @@ class TestConfig(helpers.FilesystemMockingTestCase):
95 self.patchUtils(self.tmp)90 self.patchUtils(self.tmp)
96 cc_yum_add_repo.handle('yum_add_repo', cfg, None, LOG, [])91 cc_yum_add_repo.handle('yum_add_repo', cfg, None, LOG, [])
97 contents = util.load_file("/etc/yum.repos.d/puppetlabs_products.repo")92 contents = util.load_file("/etc/yum.repos.d/puppetlabs_products.repo")
98 parser = ConfigParser()93 parser = self.parse_and_read(StringIO(contents))
99 parser.readfp(StringIO(contents))
100 expected = {94 expected = {
101 'puppetlabs_products': {95 'puppetlabs_products': {
102 'name': 'Puppet Labs Products El 6 - $basearch',96 'name': 'Puppet Labs Products El 6 - $basearch',
diff --git a/tests/unittests/test_handler/test_handler_zypper_add_repo.py b/tests/unittests/test_handler/test_handler_zypper_add_repo.py
index 315c2a5..72ab6c0 100644
--- a/tests/unittests/test_handler/test_handler_zypper_add_repo.py
+++ b/tests/unittests/test_handler/test_handler_zypper_add_repo.py
@@ -9,10 +9,6 @@ from cloudinit import util
9from cloudinit.tests import helpers9from cloudinit.tests import helpers
10from cloudinit.tests.helpers import mock10from cloudinit.tests.helpers import mock
1111
12try:
13 from configparser import ConfigParser
14except ImportError:
15 from ConfigParser import ConfigParser
16import logging12import logging
17from six import StringIO13from six import StringIO
1814
@@ -70,8 +66,7 @@ class TestConfig(helpers.FilesystemMockingTestCase):
70 root_d = self.tmp_dir()66 root_d = self.tmp_dir()
71 cc_zypper_add_repo._write_repos(cfg['repos'], root_d)67 cc_zypper_add_repo._write_repos(cfg['repos'], root_d)
72 contents = util.load_file("%s/testing-foo.repo" % root_d)68 contents = util.load_file("%s/testing-foo.repo" % root_d)
73 parser = ConfigParser()69 parser = self.parse_and_read(StringIO(contents))
74 parser.readfp(StringIO(contents))
75 expected = {70 expected = {
76 'testing-foo': {71 'testing-foo': {
77 'name': 'test-foo',72 'name': 'test-foo',
diff --git a/tests/unittests/test_reporting.py b/tests/unittests/test_reporting.py
index 571420e..e15ba6c 100644
--- a/tests/unittests/test_reporting.py
+++ b/tests/unittests/test_reporting.py
@@ -126,7 +126,7 @@ class TestBaseReportingHandler(TestCase):
126126
127 def test_base_reporting_handler_is_abstract(self):127 def test_base_reporting_handler_is_abstract(self):
128 regexp = r".*abstract.*publish_event.*"128 regexp = r".*abstract.*publish_event.*"
129 self.assertRaisesRegexp(TypeError, regexp, handlers.ReportingHandler)129 self.assertRaisesRegex(TypeError, regexp, handlers.ReportingHandler)
130130
131131
132class TestLogHandler(TestCase):132class TestLogHandler(TestCase):
diff --git a/tests/unittests/test_templating.py b/tests/unittests/test_templating.py
index b911d92..53154d3 100644
--- a/tests/unittests/test_templating.py
+++ b/tests/unittests/test_templating.py
@@ -14,7 +14,7 @@ from cloudinit import templater
14try:14try:
15 import Cheetah15 import Cheetah
16 HAS_CHEETAH = True16 HAS_CHEETAH = True
17 Cheetah # make pyflakes happy, as Cheetah is not used here17 c = Cheetah # make pyflakes and pylint happy, as Cheetah is not used here
18except ImportError:18except ImportError:
19 HAS_CHEETAH = False19 HAS_CHEETAH = False
2020
diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
index 71f5952..787ca20 100644
--- a/tests/unittests/test_util.py
+++ b/tests/unittests/test_util.py
@@ -695,9 +695,9 @@ class TestSubp(helpers.CiTestCase):
695 util.write_file(noshebang, 'true\n')695 util.write_file(noshebang, 'true\n')
696696
697 os.chmod(noshebang, os.stat(noshebang).st_mode | stat.S_IEXEC)697 os.chmod(noshebang, os.stat(noshebang).st_mode | stat.S_IEXEC)
698 self.assertRaisesRegexp(util.ProcessExecutionError,698 self.assertRaisesRegex(util.ProcessExecutionError,
699 'Missing #! in script\?',699 'Missing #! in script\?',
700 util.subp, (noshebang,))700 util.subp, (noshebang,))
701701
702 def test_returns_none_if_no_capture(self):702 def test_returns_none_if_no_capture(self):
703 (out, err) = util.subp(self.stdin2out, data=b'', capture=False)703 (out, err) = util.subp(self.stdin2out, data=b'', capture=False)
diff --git a/tests/unittests/test_vmware_config_file.py b/tests/unittests/test_vmware_config_file.py
index 808d303..0f8cda9 100644
--- a/tests/unittests/test_vmware_config_file.py
+++ b/tests/unittests/test_vmware_config_file.py
@@ -133,7 +133,8 @@ class TestVmwareConfigFile(CiTestCase):
133133
134 conf = Config(cf)134 conf = Config(cf)
135 with self.assertRaises(ValueError):135 with self.assertRaises(ValueError):
136 conf.reset_password()136 pw = conf.reset_password
137 self.assertIsNone(pw)
137138
138 cf.clear()139 cf.clear()
139 cf._insertKey("PASSWORD|RESET", "yes")140 cf._insertKey("PASSWORD|RESET", "yes")
diff --git a/tools/hacking.py b/tools/hacking.py
140deleted file mode 100755141deleted file mode 100755
index e6a0513..0000000
--- a/tools/hacking.py
+++ /dev/null
@@ -1,172 +0,0 @@
1#!/usr/bin/env python
2# Copyright (c) 2012, Cloudscaling
3# All Rights Reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
17"""cloudinit HACKING file compliance testing (based off of nova hacking.py)
18
19built on top of pep8.py
20"""
21
22import inspect
23import logging
24import re
25import sys
26
27import pep8
28
29# Don't need this for testing
30logging.disable('LOG')
31
32# N1xx comments
33# N2xx except
34# N3xx imports
35# N4xx docstrings
36# N[5-9]XX (future use)
37
38DOCSTRING_TRIPLE = ['"""', "'''"]
39VERBOSE_MISSING_IMPORT = False
40_missingImport = set([])
41
42
43def import_normalize(line):
44 # convert "from x import y" to "import x.y"
45 # handle "from x import y as z" to "import x.y as z"
46 split_line = line.split()
47 if (line.startswith("from ") and "," not in line and
48 split_line[2] == "import" and split_line[3] != "*" and
49 split_line[1] != "__future__" and
50 (len(split_line) == 4 or (len(split_line) == 6 and
51 split_line[4] == "as"))):
52 return "import %s.%s" % (split_line[1], split_line[3])
53 else:
54 return line
55
56
57def cloud_import_alphabetical(physical_line, line_number, lines):
58 """Check for imports in alphabetical order.
59
60 HACKING guide recommendation for imports:
61 imports in human alphabetical order
62 N306
63 """
64 # handle import x
65 # use .lower since capitalization shouldn't dictate order
66 split_line = import_normalize(physical_line.strip()).lower().split()
67 split_previous = import_normalize(lines[line_number - 2])
68 split_previous = split_previous.strip().lower().split()
69 # with or without "as y"
70 length = [2, 4]
71 if (len(split_line) in length and len(split_previous) in length and
72 split_line[0] == "import" and split_previous[0] == "import"):
73 if split_line[1] < split_previous[1]:
74 return (0, "N306: imports not in alphabetical order (%s, %s)"
75 % (split_previous[1], split_line[1]))
76
77
78def cloud_docstring_start_space(physical_line):
79 """Check for docstring not start with space.
80
81 HACKING guide recommendation for docstring:
82 Docstring should not start with space
83 N401
84 """
85 pos = max([physical_line.find(i) for i in DOCSTRING_TRIPLE]) # start
86 if (pos != -1 and len(physical_line) > pos + 1):
87 if (physical_line[pos + 3] == ' '):
88 return (pos,
89 "N401: one line docstring should not start with a space")
90
91
92def cloud_todo_format(physical_line):
93 """Check for 'TODO()'.
94
95 HACKING guide recommendation for TODO:
96 Include your name with TODOs as in "#TODO(termie)"
97 N101
98 """
99 pos = physical_line.find('TODO')
100 pos1 = physical_line.find('TODO(')
101 pos2 = physical_line.find('#') # make sure it's a comment
102 if (pos != pos1 and pos2 >= 0 and pos2 < pos):
103 return pos, "N101: Use TODO(NAME)"
104
105
106def cloud_docstring_one_line(physical_line):
107 """Check one line docstring end.
108
109 HACKING guide recommendation for one line docstring:
110 A one line docstring looks like this and ends in a period.
111 N402
112 """
113 pos = max([physical_line.find(i) for i in DOCSTRING_TRIPLE]) # start
114 end = max([physical_line[-4:-1] == i for i in DOCSTRING_TRIPLE]) # end
115 if (pos != -1 and end and len(physical_line) > pos + 4):
116 if (physical_line[-5] != '.'):
117 return pos, "N402: one line docstring needs a period"
118
119
120def cloud_docstring_multiline_end(physical_line):
121 """Check multi line docstring end.
122
123 HACKING guide recommendation for docstring:
124 Docstring should end on a new line
125 N403
126 """
127 pos = max([physical_line.find(i) for i in DOCSTRING_TRIPLE]) # start
128 if (pos != -1 and len(physical_line) == pos):
129 print(physical_line)
130 if (physical_line[pos + 3] == ' '):
131 return (pos, "N403: multi line docstring end on new line")
132
133
134current_file = ""
135
136
137def readlines(filename):
138 """Record the current file being tested."""
139 pep8.current_file = filename
140 return open(filename).readlines()
141
142
143def add_cloud():
144 """Monkey patch pep8 for cloud-init guidelines.
145
146 Look for functions that start with cloud_
147 and add them to pep8 module.
148
149 Assumes you know how to write pep8.py checks
150 """
151 for name, function in globals().items():
152 if not inspect.isfunction(function):
153 continue
154 if name.startswith("cloud_"):
155 exec("pep8.%s = %s" % (name, name))
156
157
158if __name__ == "__main__":
159 # NOVA based 'hacking.py' error codes start with an N
160 pep8.ERRORCODE_REGEX = re.compile(r'[EWN]\d{3}')
161 add_cloud()
162 pep8.current_file = current_file
163 pep8.readlines = readlines
164 try:
165 pep8._main()
166 finally:
167 if len(_missingImport) > 0:
168 sys.stderr.write(
169 "%i imports missing in this test environment\n" %
170 len(_missingImport))
171
172# vi: ts=4 expandtab
diff --git a/tools/make-mime.py b/tools/make-mime.py
index f6a7204..d321479 100755
--- a/tools/make-mime.py
+++ b/tools/make-mime.py
@@ -23,7 +23,7 @@ def file_content_type(text):
23 filename, content_type = text.split(":", 1)23 filename, content_type = text.split(":", 1)
24 return (open(filename, 'r'), filename, content_type.strip())24 return (open(filename, 'r'), filename, content_type.strip())
25 except ValueError:25 except ValueError:
26 raise argparse.ArgumentError("Invalid value for %r" % (text))26 raise argparse.ArgumentError(text, "Invalid value for %r" % (text))
2727
2828
29def main():29def main():
diff --git a/tools/mock-meta.py b/tools/mock-meta.py
index a5d14ab..724f7fc 100755
--- a/tools/mock-meta.py
+++ b/tools/mock-meta.py
@@ -17,6 +17,7 @@ Then:
17 ec2metadata --instance-id17 ec2metadata --instance-id
18"""18"""
1919
20import argparse
20import functools21import functools
21import json22import json
22import logging23import logging
@@ -27,8 +28,6 @@ import string
27import sys28import sys
28import yaml29import yaml
2930
30from optparse import OptionParser
31
32try:31try:
33 from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler32 from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
34 import httplib as hclient33 import httplib as hclient
@@ -415,29 +414,27 @@ def setup_logging(log_level, fmt='%(levelname)s: @%(name)s : %(message)s'):
415414
416415
417def extract_opts():416def extract_opts():
418 parser = OptionParser()417 parser = argparse.ArgumentParser()
419 parser.add_option("-p", "--port", dest="port", action="store", type=int,418 parser.add_argument("-p", "--port", dest="port", action="store", type=int,
420 default=80, metavar="PORT",419 default=80, metavar="PORT",
421 help=("port from which to serve traffic"420 help=("port from which to serve traffic"
422 " (default: %default)"))421 " (default: %default)"))
423 parser.add_option("-a", "--addr", dest="address", action="store", type=str,422 parser.add_argument("-a", "--addr", dest="address", action="store",
424 default='::', metavar="ADDRESS",423 type=str, default='::', metavar="ADDRESS",
425 help=("address from which to serve traffic"424 help=("address from which to serve traffic"
426 " (default: %default)"))425 " (default: %default)"))
427 parser.add_option("-f", '--user-data-file', dest='user_data_file',426 parser.add_argument("-f", '--user-data-file', dest='user_data_file',
428 action='store', metavar='FILE',427 action='store', metavar='FILE',
429 help=("user data filename to serve back to"428 help=("user data filename to serve back to"
430 "incoming requests"))429 "incoming requests"))
431 (options, args) = parser.parse_args()430 parser.add_argument('extra', nargs='*')
432 out = dict()431 args = parser.parse_args()
433 out['extra'] = args432 out = {'port': args.port, 'address': args.address, 'extra': args.extra,
434 out['port'] = options.port433 'user_data_file': None}
435 out['user_data_file'] = None434 if args.user_data_file:
436 out['address'] = options.address435 if not os.path.isfile(args.user_data_file):
437 if options.user_data_file:
438 if not os.path.isfile(options.user_data_file):
439 parser.error("Option -f specified a non-existent file")436 parser.error("Option -f specified a non-existent file")
440 with open(options.user_data_file, 'rb') as fh:437 with open(args.user_data_file, 'rb') as fh:
441 out['user_data_file'] = fh.read()438 out['user_data_file'] = fh.read()
442 return out439 return out
443440
diff --git a/tox.ini b/tox.ini
index 9223220..d7316cc 100644
--- a/tox.ini
+++ b/tox.ini
@@ -21,12 +21,13 @@ setenv =
21 LC_ALL = en_US.utf-821 LC_ALL = en_US.utf-8
2222
23[testenv:pylint]23[testenv:pylint]
24basepython = python3
24deps =25deps =
25 # requirements26 # requirements
26 pylint==1.7.127 pylint==1.7.1
27 # test-requirements because unit tests are now present in cloudinit tree28 # test-requirements because unit tests are now present in cloudinit tree
28 -r{toxinidir}/test-requirements.txt29 -r{toxinidir}/test-requirements.txt
29commands = {envpython} -m pylint {posargs:cloudinit}30commands = {envpython} -m pylint {posargs:cloudinit tests tools}
3031
31[testenv:py3]32[testenv:py3]
32basepython = python333basepython = python3
@@ -119,7 +120,7 @@ commands = {envpython} -m pyflakes {posargs:cloudinit/ tests/ tools/}
119deps = pyflakes120deps = pyflakes
120121
121[testenv:tip-pylint]122[testenv:tip-pylint]
122commands = {envpython} -m pylint {posargs:cloudinit}123commands = {envpython} -m pylint {posargs:cloudinit tests tools}
123deps =124deps =
124 # requirements125 # requirements
125 pylint126 pylint

Subscribers

People subscribed via source and target branches