From 305ecd817836a90a8f5e495cbf6a770dcea1f7e8 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Tue, 16 Jul 2013 11:49:04 +0200 Subject: [PATCH] Add Python 3 support These are the final changes needed to have the full py33 tox environment running and passing all tests. Change-Id: I3ac149345561a5bb99e017022ba2e2be10154584 --- oslo/config/cfg.py | 17 +++++++++++++++-- test-requirements-py3.txt | 21 +++++++++++++++++++++ tests/test_cfg.py | 16 +++++++++++----- tox.ini | 3 +++ 4 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 test-requirements-py3.txt diff --git a/oslo/config/cfg.py b/oslo/config/cfg.py index 6aafd30..2314a8a 100644 --- a/oslo/config/cfg.py +++ b/oslo/config/cfg.py @@ -370,7 +370,7 @@ class ConfigFilesNotFoundError(Error): def __str__(self): return ('Failed to read some config files: %s' % - string.join(self.config_files, ',')) + ",".join(self.config_files)) class ConfigFileParseError(Error): @@ -715,6 +715,13 @@ class Opt(object): return self._get_argparse_prefix(prefix, dgroup) + dname + def __lt__(self, another): + return hash(self) < hash(another) + +# NOTE(jd) Not available for py2.6 +if six.PY3: + Opt = functools.total_ordering(Opt) + class DeprecatedOpt(object): @@ -988,6 +995,9 @@ class SubCommandOpt(Opt): title=self.title, description=self.description, help=self.help) + # NOTE(jd) Set explicitely to True for Python 3 + # See http://bugs.python.org/issue9253 for context + subparsers.required = True if self.handler is not None: self.handler(subparsers) @@ -1610,7 +1620,10 @@ class ConfigOpts(collections.Mapping): :returns: the option value (after string subsititution) or a GroupAttr :raises: NoSuchOptError,ConfigFileValueError,TemplateSubstitutionError """ - return self._get(name) + try: + return self._get(name) + except Exception: + raise AttributeError def __getitem__(self, key): """Look up an option value and perform string substitution.""" diff --git a/test-requirements-py3.txt b/test-requirements-py3.txt new file mode 100644 index 0000000..ffcd2f3 --- /dev/null +++ b/test-requirements-py3.txt @@ -0,0 +1,21 @@ +# Install bounded pep8/pyflakes first, then let flake8 install +pep8==1.4.5 +pyflakes==0.7.2 +flake8==2.0 +hacking>=0.5.3,<0.6 + +discover +fixtures>=0.3.12 +python-subunit +-e bzr+lp:testrepository#egg=testrepository +testscenarios<0.5 +testtools>=0.9.29 + +# when we can require tox>= 1.4, this can go into tox.ini: +# [testenv:cover] +# deps = {[testenv]deps} coverage +coverage + +# this is required for the docs build jobs +sphinx +oslo.sphinx diff --git a/tests/test_cfg.py b/tests/test_cfg.py index b75f4bc..8f801c7 100644 --- a/tests/test_cfg.py +++ b/tests/test_cfg.py @@ -23,6 +23,7 @@ import fixtures import testscenarios from oslo.config import cfg +import six from six import moves from tests import utils @@ -2155,7 +2156,8 @@ class SadPathTestCase(BaseTestCase): def test_unknown_attr(self): self.conf([]) self.assertFalse(hasattr(self.conf, 'foo')) - self.assertRaises(cfg.NoSuchOptError, getattr, self.conf, 'foo') + self.assertRaises(AttributeError, getattr, self.conf, 'foo') + self.assertRaises(cfg.NoSuchOptError, self.conf._get, 'foo') def test_unknown_attr_is_attr_error(self): self.conf([]) @@ -2257,7 +2259,8 @@ class SadPathTestCase(BaseTestCase): self.conf(['--config-file', paths[0]]) - self.assertRaises(cfg.ConfigFileValueError, getattr, self.conf, 'foo') + self.assertRaises(AttributeError, getattr, self.conf, 'foo') + self.assertRaises(cfg.ConfigFileValueError, self.conf._get, 'foo') def test_conf_file_bad_bool(self): self._do_test_conf_file_bad_value(cfg.BoolOpt) @@ -2277,7 +2280,9 @@ class SadPathTestCase(BaseTestCase): self.assertFalse(hasattr(self.conf, 'bar')) self.assertRaises( - cfg.TemplateSubstitutionError, getattr, self.conf, 'bar') + AttributeError, getattr, self.conf, 'bar') + self.assertRaises( + cfg.TemplateSubstitutionError, self.conf._get, 'bar') def test_set_default_unknown_attr(self): self.conf([]) @@ -2438,7 +2443,7 @@ class ConfigParserTestCase(BaseTestCase): def test_no_section(self): with tempfile.NamedTemporaryFile() as tmpfile: - tmpfile.write('foo = bar') + tmpfile.write(six.b('foo = bar')) tmpfile.flush() parser = cfg.ConfigParser(tmpfile.name, {}) @@ -2812,7 +2817,8 @@ class ChoicesTestCase(BaseTestCase): self.conf(['--config-file', paths[0]]) - self.assertRaises(cfg.ConfigFileValueError, getattr, self.conf, 'foo') + self.assertRaises(cfg.ConfigFileValueError, self.conf._get, 'foo') + self.assertRaises(AttributeError, getattr, self.conf, 'foo') def test_conf_file_choice_value_override(self): self.conf.register_cli_opt(cfg.StrOpt('foo', diff --git a/tox.ini b/tox.ini index 4e9eac1..e0c8da1 100644 --- a/tox.ini +++ b/tox.ini @@ -7,6 +7,9 @@ deps = -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt commands = python setup.py testr --slowest --testr-args='{posargs}' +[testenv:py33] +deps = -r{toxinidir}/test-requirements-py3.txt + [testenv:pep8] commands = flake8