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
This commit is contained in:
Julien Danjou 2013-07-16 11:49:04 +02:00
parent b96ebd3e5d
commit 305ecd8178
4 changed files with 50 additions and 7 deletions

View File

@ -370,7 +370,7 @@ class ConfigFilesNotFoundError(Error):
def __str__(self): def __str__(self):
return ('Failed to read some config files: %s' % return ('Failed to read some config files: %s' %
string.join(self.config_files, ',')) ",".join(self.config_files))
class ConfigFileParseError(Error): class ConfigFileParseError(Error):
@ -715,6 +715,13 @@ class Opt(object):
return self._get_argparse_prefix(prefix, dgroup) + dname 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): class DeprecatedOpt(object):
@ -988,6 +995,9 @@ class SubCommandOpt(Opt):
title=self.title, title=self.title,
description=self.description, description=self.description,
help=self.help) 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: if self.handler is not None:
self.handler(subparsers) self.handler(subparsers)
@ -1610,7 +1620,10 @@ class ConfigOpts(collections.Mapping):
:returns: the option value (after string subsititution) or a GroupAttr :returns: the option value (after string subsititution) or a GroupAttr
:raises: NoSuchOptError,ConfigFileValueError,TemplateSubstitutionError :raises: NoSuchOptError,ConfigFileValueError,TemplateSubstitutionError
""" """
return self._get(name) try:
return self._get(name)
except Exception:
raise AttributeError
def __getitem__(self, key): def __getitem__(self, key):
"""Look up an option value and perform string substitution.""" """Look up an option value and perform string substitution."""

21
test-requirements-py3.txt Normal file
View File

@ -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

View File

@ -23,6 +23,7 @@ import fixtures
import testscenarios import testscenarios
from oslo.config import cfg from oslo.config import cfg
import six
from six import moves from six import moves
from tests import utils from tests import utils
@ -2155,7 +2156,8 @@ class SadPathTestCase(BaseTestCase):
def test_unknown_attr(self): def test_unknown_attr(self):
self.conf([]) self.conf([])
self.assertFalse(hasattr(self.conf, 'foo')) 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): def test_unknown_attr_is_attr_error(self):
self.conf([]) self.conf([])
@ -2257,7 +2259,8 @@ class SadPathTestCase(BaseTestCase):
self.conf(['--config-file', paths[0]]) 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): def test_conf_file_bad_bool(self):
self._do_test_conf_file_bad_value(cfg.BoolOpt) self._do_test_conf_file_bad_value(cfg.BoolOpt)
@ -2277,7 +2280,9 @@ class SadPathTestCase(BaseTestCase):
self.assertFalse(hasattr(self.conf, 'bar')) self.assertFalse(hasattr(self.conf, 'bar'))
self.assertRaises( 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): def test_set_default_unknown_attr(self):
self.conf([]) self.conf([])
@ -2438,7 +2443,7 @@ class ConfigParserTestCase(BaseTestCase):
def test_no_section(self): def test_no_section(self):
with tempfile.NamedTemporaryFile() as tmpfile: with tempfile.NamedTemporaryFile() as tmpfile:
tmpfile.write('foo = bar') tmpfile.write(six.b('foo = bar'))
tmpfile.flush() tmpfile.flush()
parser = cfg.ConfigParser(tmpfile.name, {}) parser = cfg.ConfigParser(tmpfile.name, {})
@ -2812,7 +2817,8 @@ class ChoicesTestCase(BaseTestCase):
self.conf(['--config-file', paths[0]]) 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): def test_conf_file_choice_value_override(self):
self.conf.register_cli_opt(cfg.StrOpt('foo', self.conf.register_cli_opt(cfg.StrOpt('foo',

View File

@ -7,6 +7,9 @@ deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt -r{toxinidir}/test-requirements.txt
commands = python setup.py testr --slowest --testr-args='{posargs}' commands = python setup.py testr --slowest --testr-args='{posargs}'
[testenv:py33]
deps = -r{toxinidir}/test-requirements-py3.txt
[testenv:pep8] [testenv:pep8]
commands = flake8 commands = flake8