summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS15
-rw-r--r--README11
-rw-r--r--README.rst31
-rw-r--r--contrib/redhat-eventlet.patch16
-rw-r--r--doc/source/conf.py8
-rw-r--r--openstack/common/lockutils.py29
-rw-r--r--openstack/common/processutils.py66
-rw-r--r--openstack/common/rootwrap/filters.py20
-rw-r--r--openstack/common/rootwrap/wrapper.py8
-rw-r--r--openstack/common/rpc/impl_qpid.py2
-rw-r--r--openstack/common/strutils.py15
-rw-r--r--tests/unit/rpc/test_common.py8
-rw-r--r--tests/unit/test_lockutils.py16
-rw-r--r--tests/unit/test_processutils.py85
-rw-r--r--tests/unit/test_strutils.py94
-rw-r--r--tests/unit/test_timeutils.py26
-rw-r--r--tests/unit/test_wsgi.py3
-rw-r--r--tools/patch_tox_venv.py38
-rw-r--r--tox.ini4
-rw-r--r--update.py7
20 files changed, 392 insertions, 110 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 83822b1..55bc962 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -205,6 +205,13 @@ M: Michael Still <mikal@stillhq.com>
S: Maintained
F: processutils.py
+== redhat-eventlet.patch ==
+
+M: Mark McLoughlin <markmc@redhat.com>
+S: Maintained
+F: contrib/redhat-eventlet.patch
+F: tools/patch_tox_venv.py
+
== rootwrap ==
M: Thierry Carrez <thierry@openstack.org>
@@ -250,14 +257,14 @@ F: threadgroup.py
== timeutils ==
-M:
-S: Orphan
+M: Zhongyue Luo <zhongyue.nah@intel.com>
+S: Maintained
F: timeutils.py
== uuidutils ==
-M:
-S: Orphan
+M: Zhongyue Luo <zhongyue.nah@intel.com>
+S: Maintained
F: uuidutils.py
== wsgi ==
diff --git a/README b/README
deleted file mode 100644
index 04da07e..0000000
--- a/README
+++ /dev/null
@@ -1,11 +0,0 @@
-Common code for Openstack Projects.
-
-To run tests in virtualenvs (preferred):
-
- sudo pip install tox
- tox
-
-To run tests in the current environment:
-
- sudo pip install -r tools/pip-requires
- nosetests
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..33b88ab
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,31 @@
+------------------
+The Oslo Incubator
+------------------
+
+The Oslo program produces a set of python libraries containing
+infrastructure code shared by OpenStack projects. The APIs provided by
+these libraries should be high quality, stable, consistent and
+generally useful.
+
+The process of developing a new Oslo API usually begins by taking code
+which is common to some OpenStack projects and moving it into this
+repository. Incubation shouldn't be seen as a long term option for any
+API - it is merely a stepping stone to inclusion into a published Oslo
+library.
+
+For more information, see our wiki page:
+
+ https://wiki.openstack.org/wiki/Oslo
+
+Running Tests
+-------------
+
+To run tests in virtualenvs (preferred):
+
+ sudo pip install tox
+ tox
+
+To run tests in the current environment:
+
+ sudo pip install -r tools/pip-requires
+ nosetests
diff --git a/contrib/redhat-eventlet.patch b/contrib/redhat-eventlet.patch
new file mode 100644
index 0000000..cf2ff53
--- /dev/null
+++ b/contrib/redhat-eventlet.patch
@@ -0,0 +1,16 @@
+--- .nova-venv/lib/python2.6/site-packages/eventlet/green/subprocess.py.orig
+2011-05-25
+23:31:34.597271402 +0000
++++ .nova-venv/lib/python2.6/site-packages/eventlet/green/subprocess.py
+2011-05-25
+23:33:24.055602468 +0000
+@@ -32,7 +32,7 @@
+ setattr(self, attr, wrapped_pipe)
+ __init__.__doc__ = subprocess_orig.Popen.__init__.__doc__
+
+- def wait(self, check_interval=0.01):
++ def wait(self, check_interval=0.01, timeout=None):
+ # Instead of a blocking OS call, this version of wait() uses logic
+ # borrowed from the eventlet 0.2 processes.Process.wait() method.
+ try:
+
diff --git a/doc/source/conf.py b/doc/source/conf.py
index d126a23..9088cfe 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -24,8 +24,8 @@ source_suffix = '.rst'
master_doc = 'index'
# General information about the project.
-project = u'Oslo'
-copyright = u'2012, OpenStack Foundation'
+project = 'Oslo'
+copyright = '2012, OpenStack Foundation'
# If true, '()' will be appended to :func: etc. cross-reference text.
add_function_parentheses = True
@@ -57,8 +57,8 @@ html_last_updated_fmt = os.popen(git_cmd).read()
latex_documents = [
('index',
'%s.tex' % project,
- u'%s Documentation' % project,
- u'OpenStack Foundation', 'manual'),
+ '%s Documentation' % project,
+ 'OpenStack Foundation', 'manual'),
]
# Example configuration for intersphinx: refer to the Python standard library.
diff --git a/openstack/common/lockutils.py b/openstack/common/lockutils.py
index 892d821..79d1905 100644
--- a/openstack/common/lockutils.py
+++ b/openstack/common/lockutils.py
@@ -49,6 +49,10 @@ CONF = cfg.CONF
CONF.register_opts(util_opts)
+def set_defaults(lock_path):
+ cfg.set_defaults(util_opts, lock_path=lock_path)
+
+
class _InterProcessLock(object):
"""Lock implementation which allows multiple locks, working around
issues like bugs.debian.org/cgi-bin/bugreport.cgi?bug=632857 and does
@@ -247,3 +251,28 @@ def synchronized(name, lock_file_prefix, external=False, lock_path=None):
return retval
return inner
return wrap
+
+
+def synchronized_with_prefix(lock_file_prefix):
+ """Partial object generator for the synchronization decorator.
+
+ Redefine @synchronized in each project like so::
+
+ (in nova/utils.py)
+ from nova.openstack.common import lockutils
+
+ synchronized = lockutils.synchronized_with_prefix('nova-')
+
+
+ (in nova/foo.py)
+ from nova import utils
+
+ @utils.synchronized('mylock')
+ def bar(self, *args):
+ ...
+
+ The lock_file_prefix argument is used to provide lock files on disk with a
+ meaningful prefix. The prefix should end with a hyphen ('-') if specified.
+ """
+
+ return functools.partial(synchronized, lock_file_prefix=lock_file_prefix)
diff --git a/openstack/common/processutils.py b/openstack/common/processutils.py
index 560055e..09baea3 100644
--- a/openstack/common/processutils.py
+++ b/openstack/common/processutils.py
@@ -34,6 +34,11 @@ from openstack.common import log as logging
LOG = logging.getLogger(__name__)
+class InvalidArgumentError(Exception):
+ def __init__(self, message=None):
+ super(InvalidArgumentError, self).__init__(message)
+
+
class UnknownArgumentError(Exception):
def __init__(self, message=None):
super(UnknownArgumentError, self).__init__(message)
@@ -179,3 +184,64 @@ def execute(*cmd, **kwargs):
# call clean something up in between calls, without
# it two execute calls in a row hangs the second one
greenthread.sleep(0)
+
+
+def trycmd(*args, **kwargs):
+ """
+ A wrapper around execute() to more easily handle warnings and errors.
+
+ Returns an (out, err) tuple of strings containing the output of
+ the command's stdout and stderr. If 'err' is not empty then the
+ command can be considered to have failed.
+
+ :discard_warnings True | False. Defaults to False. If set to True,
+ then for succeeding commands, stderr is cleared
+
+ """
+ discard_warnings = kwargs.pop('discard_warnings', False)
+
+ try:
+ out, err = execute(*args, **kwargs)
+ failed = False
+ except ProcessExecutionError, exn:
+ out, err = '', str(exn)
+ failed = True
+
+ if not failed and discard_warnings and err:
+ # Handle commands that output to stderr but otherwise succeed
+ err = ''
+
+ return out, err
+
+
+def ssh_execute(ssh, cmd, process_input=None,
+ addl_env=None, check_exit_code=True):
+ LOG.debug(_('Running cmd (SSH): %s'), cmd)
+ if addl_env:
+ raise InvalidArgumentError(_('Environment not supported over SSH'))
+
+ if process_input:
+ # This is (probably) fixable if we need it...
+ raise InvalidArgumentError(_('process_input not supported over SSH'))
+
+ stdin_stream, stdout_stream, stderr_stream = ssh.exec_command(cmd)
+ channel = stdout_stream.channel
+
+ # NOTE(justinsb): This seems suspicious...
+ # ...other SSH clients have buffering issues with this approach
+ stdout = stdout_stream.read()
+ stderr = stderr_stream.read()
+ stdin_stream.close()
+
+ exit_status = channel.recv_exit_status()
+
+ # exit_status == -1 if no exit code was returned
+ if exit_status != -1:
+ LOG.debug(_('Result was %s') % exit_status)
+ if check_exit_code and exit_status != 0:
+ raise ProcessExecutionError(exit_code=exit_status,
+ stdout=stdout,
+ stderr=stderr,
+ cmd=cmd)
+
+ return (stdout, stderr)
diff --git a/openstack/common/rootwrap/filters.py b/openstack/common/rootwrap/filters.py
index d9618af..58121cb 100644
--- a/openstack/common/rootwrap/filters.py
+++ b/openstack/common/rootwrap/filters.py
@@ -20,7 +20,7 @@ import re
class CommandFilter(object):
- """Command filter only checking that the 1st argument matches exec_path"""
+ """Command filter only checking that the 1st argument matches exec_path."""
def __init__(self, exec_path, run_as, *args):
self.name = ''
@@ -30,7 +30,7 @@ class CommandFilter(object):
self.real_exec = None
def get_exec(self, exec_dirs=[]):
- """Returns existing executable, or empty string if none found"""
+ """Returns existing executable, or empty string if none found."""
if self.real_exec is not None:
return self.real_exec
self.real_exec = ""
@@ -46,10 +46,8 @@ class CommandFilter(object):
return self.real_exec
def match(self, userargs):
- """Only check that the first argument (command) matches exec_path"""
- if (os.path.basename(self.exec_path) == userargs[0]):
- return True
- return False
+ """Only check that the first argument (command) matches exec_path."""
+ return os.path.basename(self.exec_path) == userargs[0]
def get_command(self, userargs, exec_dirs=[]):
"""Returns command to execute (with sudo -u if run_as != root)."""
@@ -60,12 +58,12 @@ class CommandFilter(object):
return [to_exec] + userargs[1:]
def get_environment(self, userargs):
- """Returns specific environment to set, None if none"""
+ """Returns specific environment to set, None if none."""
return None
class RegExpFilter(CommandFilter):
- """Command filter doing regexp matching for every argument"""
+ """Command filter doing regexp matching for every argument."""
def match(self, userargs):
# Early skip if command or number of args don't match
@@ -135,7 +133,7 @@ class PathFilter(CommandFilter):
class DnsmasqFilter(CommandFilter):
- """Specific filter for the dnsmasq call (which includes env)"""
+ """Specific filter for the dnsmasq call (which includes env)."""
CONFIG_FILE_ARG = 'CONFIG_FILE'
@@ -160,7 +158,7 @@ class DnsmasqFilter(CommandFilter):
class DeprecatedDnsmasqFilter(DnsmasqFilter):
- """Variant of dnsmasq filter to support old-style FLAGFILE"""
+ """Variant of dnsmasq filter to support old-style FLAGFILE."""
CONFIG_FILE_ARG = 'FLAGFILE'
@@ -210,7 +208,7 @@ class KillFilter(CommandFilter):
class ReadFileFilter(CommandFilter):
- """Specific filter for the utils.read_file_as_root call"""
+ """Specific filter for the utils.read_file_as_root call."""
def __init__(self, file_path, *args):
self.file_path = file_path
diff --git a/openstack/common/rootwrap/wrapper.py b/openstack/common/rootwrap/wrapper.py
index e0ac9df..d488ddd 100644
--- a/openstack/common/rootwrap/wrapper.py
+++ b/openstack/common/rootwrap/wrapper.py
@@ -93,7 +93,7 @@ def setup_syslog(execname, facility, level):
def build_filter(class_name, *args):
- """Returns a filter object of class class_name"""
+ """Returns a filter object of class class_name."""
if not hasattr(filters, class_name):
logging.warning("Skipping unknown filter class (%s) specified "
"in filter definitions" % class_name)
@@ -103,7 +103,7 @@ def build_filter(class_name, *args):
def load_filters(filters_path):
- """Load filters from a list of directories"""
+ """Load filters from a list of directories."""
filterlist = []
for filterdir in filters_path:
if not os.path.isdir(filterdir):
@@ -121,7 +121,7 @@ def load_filters(filters_path):
return filterlist
-def match_filter(filters, userargs, exec_dirs=[]):
+def match_filter(filter_list, userargs, exec_dirs=[]):
"""
Checks user command and arguments through command filters and
returns the first matching filter.
@@ -131,7 +131,7 @@ def match_filter(filters, userargs, exec_dirs=[]):
"""
first_not_executable_filter = None
- for f in filters:
+ for f in filter_list:
if f.match(userargs):
# Try other filters if executable is absent
if not f.get_exec(exec_dirs=exec_dirs):
diff --git a/openstack/common/rpc/impl_qpid.py b/openstack/common/rpc/impl_qpid.py
index a7b4707..a03ebb2 100644
--- a/openstack/common/rpc/impl_qpid.py
+++ b/openstack/common/rpc/impl_qpid.py
@@ -375,7 +375,7 @@ class Connection(object):
try:
return method(*args, **kwargs)
except (qpid_exceptions.Empty,
- qpid_exceptions.ConnectionError), e:
+ qpid_exceptions.ConnectionError) as e:
if error_callback:
error_callback(e)
self.reconnect()
diff --git a/openstack/common/strutils.py b/openstack/common/strutils.py
index fe8418e..d6dfb13 100644
--- a/openstack/common/strutils.py
+++ b/openstack/common/strutils.py
@@ -49,12 +49,15 @@ def bool_from_string(subject):
Useful for JSON-decoded stuff and config file parsing
"""
- if isinstance(subject, bool):
- return subject
- if isinstance(subject, basestring):
- if subject.strip().lower() in ('true', 'on', 'yes', '1'):
- return True
- return False
+ try:
+ # True or 1 or '1' -> True
+ # False or < 1 or > 1 or '0' -> False
+ return int(subject) == 1
+ except TypeError:
+ # None -> False
+ return False
+ except ValueError:
+ return subject.strip().lower() in ('true', 'on', 'yes')
def safe_decode(text, incoming=None, errors='strict'):
diff --git a/tests/unit/rpc/test_common.py b/tests/unit/rpc/test_common.py
index 18951df..1f07ff7 100644
--- a/tests/unit/rpc/test_common.py
+++ b/tests/unit/rpc/test_common.py
@@ -153,15 +153,15 @@ class RpcCommonTestCase(test_utils.BaseTestCase):
'class': 'FakeUserDefinedException',
'module': self.__class__.__module__,
'tb': ['raise FakeUserDefinedException'],
- 'args': (u'fakearg',),
- 'kwargs': {u'fakekwarg': u'fake'},
+ 'args': ('fakearg',),
+ 'kwargs': {'fakekwarg': 'fake'},
}
serialized = jsonutils.dumps(failure)
after_exc = rpc_common.deserialize_remote_exception(FLAGS, serialized)
self.assertTrue(isinstance(after_exc, FakeUserDefinedException))
- self.assertEqual(after_exc.args, (u'fakearg',))
- self.assertEqual(after_exc.kwargs, {u'fakekwarg': u'fake'})
+ self.assertEqual(after_exc.args, ('fakearg',))
+ self.assertEqual(after_exc.kwargs, {'fakekwarg': 'fake'})
def test_deserialize_remote_exception_cannot_recreate(self):
"""Ensure a RemoteError is returned on initialization failure.
diff --git a/tests/unit/test_lockutils.py b/tests/unit/test_lockutils.py
index 1230569..c37b030 100644
--- a/tests/unit/test_lockutils.py
+++ b/tests/unit/test_lockutils.py
@@ -195,3 +195,19 @@ class LockTestCase(utils.BaseTestCase):
finally:
if os.path.exists(lock_dir):
shutil.rmtree(lock_dir, ignore_errors=True)
+
+ def test_synchronized_with_prefix(self):
+ lock_name = 'mylock'
+ lock_pfix = 'mypfix-'
+
+ foo = lockutils.synchronized_with_prefix(lock_pfix)
+
+ @foo(lock_name, external=True)
+ def bar(dirpath, pfix, name):
+ filepath = os.path.join(dirpath, '%s%s' % (pfix, name))
+ return os.path.isfile(filepath)
+
+ lock_dir = tempfile.mkdtemp()
+ self.config(lock_path=lock_dir)
+
+ self.assertTrue(bar(lock_dir, lock_pfix, lock_name))
diff --git a/tests/unit/test_processutils.py b/tests/unit/test_processutils.py
index 2b99d24..e00a66e 100644
--- a/tests/unit/test_processutils.py
+++ b/tests/unit/test_processutils.py
@@ -17,7 +17,9 @@
from __future__ import print_function
+import fixtures
import os
+import StringIO
import tempfile
from openstack.common import processutils
@@ -164,3 +166,86 @@ grep foo
finally:
os.unlink(tmpfilename)
os.unlink(tmpfilename2)
+
+
+def fake_execute(*cmd, **kwargs):
+ return 'stdout', 'stderr'
+
+
+def fake_execute_raises(*cmd, **kwargs):
+ raise processutils.ProcessExecutionError(exit_code=42,
+ stdout='stdout',
+ stderr='stderr',
+ cmd=['this', 'is', 'a',
+ 'command'])
+
+
+class TryCmdTestCase(utils.BaseTestCase):
+ def test_keep_warnings(self):
+ self.useFixture(fixtures.MonkeyPatch(
+ 'openstack.common.processutils.execute', fake_execute))
+ o, e = processutils.trycmd('this is a command'.split(' '))
+ self.assertNotEqual('', o)
+ self.assertNotEqual('', e)
+
+ def test_keep_warnings_from_raise(self):
+ self.useFixture(fixtures.MonkeyPatch(
+ 'openstack.common.processutils.execute', fake_execute_raises))
+ o, e = processutils.trycmd('this is a command'.split(' '),
+ discard_warnings=True)
+ self.assertNotEqual(None, o)
+ self.assertNotEqual('', e)
+
+ def test_discard_warnings(self):
+ self.useFixture(fixtures.MonkeyPatch(
+ 'openstack.common.processutils.execute', fake_execute))
+ o, e = processutils.trycmd('this is a command'.split(' '),
+ discard_warnings=True)
+ self.assertNotEqual(None, o)
+ self.assertEqual('', e)
+
+
+class FakeSshChannel(object):
+ def __init__(self, rc):
+ self.rc = rc
+
+ def recv_exit_status(self):
+ return self.rc
+
+
+class FakeSshStream(StringIO.StringIO):
+ def setup_channel(self, rc):
+ self.channel = FakeSshChannel(rc)
+
+
+class FakeSshConnection(object):
+ def __init__(self, rc):
+ self.rc = rc
+
+ def exec_command(self, cmd):
+ stdout = FakeSshStream('stdout')
+ stdout.setup_channel(self.rc)
+ return (StringIO.StringIO(),
+ stdout,
+ StringIO.StringIO('stderr'))
+
+
+class SshExecuteTestCase(utils.BaseTestCase):
+ def test_invalid_addl_env(self):
+ self.assertRaises(processutils.InvalidArgumentError,
+ processutils.ssh_execute,
+ None, 'ls', addl_env='important')
+
+ def test_invalid_process_input(self):
+ self.assertRaises(processutils.InvalidArgumentError,
+ processutils.ssh_execute,
+ None, 'ls', process_input='important')
+
+ def test_works(self):
+ o, e = processutils.ssh_execute(FakeSshConnection(0), 'ls')
+ self.assertEqual('stdout', o)
+ self.assertEqual('stderr', e)
+
+ def test_fails(self):
+ self.assertRaises(processutils.ProcessExecutionError,
+ processutils.ssh_execute, FakeSshConnection(1), 'ls')
diff --git a/tests/unit/test_strutils.py b/tests/unit/test_strutils.py
index e2c4622..b0af958 100644
--- a/tests/unit/test_strutils.py
+++ b/tests/unit/test_strutils.py
@@ -16,6 +16,7 @@
# under the License.
import mock
+import six
from openstack.common import strutils
from tests import utils
@@ -27,48 +28,47 @@ class StrUtilsTest(utils.BaseTestCase):
self.assertTrue(strutils.bool_from_string(True))
self.assertFalse(strutils.bool_from_string(False))
- def test_str_bool_from_string(self):
- self.assertTrue(strutils.bool_from_string('true'))
- self.assertTrue(strutils.bool_from_string('TRUE'))
- self.assertTrue(strutils.bool_from_string('on'))
- self.assertTrue(strutils.bool_from_string('On'))
- self.assertTrue(strutils.bool_from_string('yes'))
- self.assertTrue(strutils.bool_from_string('YES'))
- self.assertTrue(strutils.bool_from_string('yEs'))
- self.assertTrue(strutils.bool_from_string('1'))
-
- self.assertFalse(strutils.bool_from_string('false'))
- self.assertFalse(strutils.bool_from_string('FALSE'))
- self.assertFalse(strutils.bool_from_string('off'))
- self.assertFalse(strutils.bool_from_string('OFF'))
- self.assertFalse(strutils.bool_from_string('no'))
- self.assertFalse(strutils.bool_from_string('0'))
- self.assertFalse(strutils.bool_from_string('42'))
- self.assertFalse(strutils.bool_from_string('This should not be True'))
+ def _test_bool_from_string(self, c):
+ self.assertTrue(strutils.bool_from_string(c('true')))
+ self.assertTrue(strutils.bool_from_string(c('TRUE')))
+ self.assertTrue(strutils.bool_from_string(c('on')))
+ self.assertTrue(strutils.bool_from_string(c('On')))
+ self.assertTrue(strutils.bool_from_string(c('yes')))
+ self.assertTrue(strutils.bool_from_string(c('YES')))
+ self.assertTrue(strutils.bool_from_string(c('yEs')))
+ self.assertTrue(strutils.bool_from_string(c('1')))
+
+ self.assertFalse(strutils.bool_from_string(c('false')))
+ self.assertFalse(strutils.bool_from_string(c('FALSE')))
+ self.assertFalse(strutils.bool_from_string(c('off')))
+ self.assertFalse(strutils.bool_from_string(c('OFF')))
+ self.assertFalse(strutils.bool_from_string(c('no')))
+ self.assertFalse(strutils.bool_from_string(c('0')))
+ self.assertFalse(strutils.bool_from_string(c('42')))
+ self.assertFalse(strutils.bool_from_string(c(
+ 'This should not be True')))
+
+ # Whitespace should be stripped
+ self.assertTrue(strutils.bool_from_string(c(' true ')))
+ self.assertFalse(strutils.bool_from_string(c(' false ')))
+
+ def test_bool_from_string(self):
+ self._test_bool_from_string(lambda s: s)
def test_unicode_bool_from_string(self):
- self.assertTrue(strutils.bool_from_string(u'true'))
- self.assertTrue(strutils.bool_from_string(u'TRUE'))
- self.assertTrue(strutils.bool_from_string(u'on'))
- self.assertTrue(strutils.bool_from_string(u'On'))
- self.assertTrue(strutils.bool_from_string(u'yes'))
- self.assertTrue(strutils.bool_from_string(u'YES'))
- self.assertTrue(strutils.bool_from_string(u'yEs'))
- self.assertTrue(strutils.bool_from_string(u'1'))
-
- self.assertFalse(strutils.bool_from_string(u'false'))
- self.assertFalse(strutils.bool_from_string(u'FALSE'))
- self.assertFalse(strutils.bool_from_string(u'off'))
- self.assertFalse(strutils.bool_from_string(u'OFF'))
- self.assertFalse(strutils.bool_from_string(u'no'))
- self.assertFalse(strutils.bool_from_string(u'NO'))
- self.assertFalse(strutils.bool_from_string(u'0'))
- self.assertFalse(strutils.bool_from_string(u'42'))
- self.assertFalse(strutils.bool_from_string(u'This should not be True'))
+ self._test_bool_from_string(six.text_type)
def test_other_bool_from_string(self):
+ self.assertFalse(strutils.bool_from_string(None))
self.assertFalse(strutils.bool_from_string(mock.Mock()))
+ def test_int_bool_from_string(self):
+ self.assertTrue(strutils.bool_from_string(1))
+
+ self.assertFalse(strutils.bool_from_string(-1))
+ self.assertFalse(strutils.bool_from_string(0))
+ self.assertFalse(strutils.bool_from_string(2))
+
def test_int_from_bool_as_string(self):
self.assertEqual(1, strutils.int_from_bool_as_string(True))
self.assertEqual(0, strutils.int_from_bool_as_string(False))
@@ -76,25 +76,25 @@ class StrUtilsTest(utils.BaseTestCase):
def test_safe_decode(self):
safe_decode = strutils.safe_decode
self.assertRaises(TypeError, safe_decode, True)
- self.assertEqual(u'ni\xf1o', safe_decode("ni\xc3\xb1o",
- incoming="utf-8"))
- self.assertEqual(u"test", safe_decode("dGVzdA==",
- incoming='base64'))
+ self.assertEqual(six.u('ni\xf1o'), safe_decode("ni\xc3\xb1o",
+ incoming="utf-8"))
+ self.assertEqual(six.u("test"), safe_decode("dGVzdA==",
+ incoming='base64'))
- self.assertEqual(u"strange", safe_decode('\x80strange',
- errors='ignore'))
+ self.assertEqual(six.u("strange"), safe_decode('\x80strange',
+ errors='ignore'))
- self.assertEqual(u'\xc0', safe_decode('\xc0',
- incoming='iso-8859-1'))
+ self.assertEqual(six.u('\xc0'), safe_decode('\xc0',
+ incoming='iso-8859-1'))
# Forcing incoming to ascii so it falls back to utf-8
- self.assertEqual(u'ni\xf1o', safe_decode('ni\xc3\xb1o',
- incoming='ascii'))
+ self.assertEqual(six.u('ni\xf1o'), safe_decode('ni\xc3\xb1o',
+ incoming='ascii'))
def test_safe_encode(self):
safe_encode = strutils.safe_encode
self.assertRaises(TypeError, safe_encode, True)
- self.assertEqual("ni\xc3\xb1o", safe_encode(u'ni\xf1o',
+ self.assertEqual("ni\xc3\xb1o", safe_encode(six.u('ni\xf1o'),
encoding="utf-8"))
self.assertEqual("dGVzdA==\n", safe_encode("test",
encoding='base64'))
diff --git a/tests/unit/test_timeutils.py b/tests/unit/test_timeutils.py
index bcb6a69..bfab278 100644
--- a/tests/unit/test_timeutils.py
+++ b/tests/unit/test_timeutils.py
@@ -201,31 +201,31 @@ class TestIso8601Time(utils.BaseTestCase):
def test_zulu(self):
str = '2012-02-14T20:53:07Z'
- self._do_test(str, 2012, 02, 14, 20, 53, 7, 0, 0)
+ self._do_test(str, 2012, 2, 14, 20, 53, 7, 0, 0)
def test_zulu_micros(self):
str = '2012-02-14T20:53:07.123Z'
- self._do_test(str, 2012, 02, 14, 20, 53, 7, 123000, 0)
+ self._do_test(str, 2012, 2, 14, 20, 53, 7, 123000, 0)
def test_offset_east(self):
str = '2012-02-14T20:53:07+04:30'
offset = 4.5 * 60 * 60
- self._do_test(str, 2012, 02, 14, 20, 53, 7, 0, offset)
+ self._do_test(str, 2012, 2, 14, 20, 53, 7, 0, offset)
def test_offset_east_micros(self):
str = '2012-02-14T20:53:07.42+04:30'
offset = 4.5 * 60 * 60
- self._do_test(str, 2012, 02, 14, 20, 53, 7, 420000, offset)
+ self._do_test(str, 2012, 2, 14, 20, 53, 7, 420000, offset)
def test_offset_west(self):
str = '2012-02-14T20:53:07-05:30'
offset = -5.5 * 60 * 60
- self._do_test(str, 2012, 02, 14, 20, 53, 7, 0, offset)
+ self._do_test(str, 2012, 2, 14, 20, 53, 7, 0, offset)
def test_offset_west_micros(self):
str = '2012-02-14T20:53:07.654321-05:30'
offset = -5.5 * 60 * 60
- self._do_test(str, 2012, 02, 14, 20, 53, 7, 654321, offset)
+ self._do_test(str, 2012, 2, 14, 20, 53, 7, 654321, offset)
def test_compare(self):
zulu = timeutils.parse_isotime('2012-02-14T20:53:07')
@@ -271,36 +271,36 @@ class TestIso8601Time(utils.BaseTestCase):
str = '2012-02-14T20:53:07Z'
zulu = timeutils.parse_isotime(str)
normed = timeutils.normalize_time(zulu)
- self._instaneous(normed, 2012, 2, 14, 20, 53, 07, 0)
+ self._instaneous(normed, 2012, 2, 14, 20, 53, 7, 0)
def test_east_normalize(self):
str = '2012-02-14T20:53:07-07:00'
east = timeutils.parse_isotime(str)
normed = timeutils.normalize_time(east)
- self._instaneous(normed, 2012, 2, 15, 03, 53, 07, 0)
+ self._instaneous(normed, 2012, 2, 15, 3, 53, 7, 0)
def test_west_normalize(self):
str = '2012-02-14T20:53:07+21:00'
west = timeutils.parse_isotime(str)
normed = timeutils.normalize_time(west)
- self._instaneous(normed, 2012, 2, 13, 23, 53, 07, 0)
+ self._instaneous(normed, 2012, 2, 13, 23, 53, 7, 0)
def test_normalize_aware_to_naive(self):
- dt = datetime.datetime(2011, 2, 14, 20, 53, 07)
+ dt = datetime.datetime(2011, 2, 14, 20, 53, 7)
str = '2011-02-14T20:53:07+21:00'
aware = timeutils.parse_isotime(str)
naive = timeutils.normalize_time(aware)
self.assertTrue(naive < dt)
def test_normalize_zulu_aware_to_naive(self):
- dt = datetime.datetime(2011, 2, 14, 20, 53, 07)
+ dt = datetime.datetime(2011, 2, 14, 20, 53, 7)
str = '2011-02-14T19:53:07Z'
aware = timeutils.parse_isotime(str)
naive = timeutils.normalize_time(aware)
self.assertTrue(naive < dt)
def test_normalize_naive(self):
- dt = datetime.datetime(2011, 2, 14, 20, 53, 07)
- dtn = datetime.datetime(2011, 2, 14, 19, 53, 07)
+ dt = datetime.datetime(2011, 2, 14, 20, 53, 7)
+ dtn = datetime.datetime(2011, 2, 14, 19, 53, 7)
naive = timeutils.normalize_time(dtn)
self.assertTrue(naive < dt)
diff --git a/tests/unit/test_wsgi.py b/tests/unit/test_wsgi.py
index 94d8092..a3a4d32 100644
--- a/tests/unit/test_wsgi.py
+++ b/tests/unit/test_wsgi.py
@@ -21,6 +21,7 @@ import urllib2
import mock
import routes
+import six
import webob
from openstack.common import exception
@@ -189,7 +190,7 @@ class JSONDictSerializerTest(utils.BaseTestCase):
def test_object_unicode(self):
class TestUnicode:
def __unicode__(self):
- return u'TestUnicode'
+ return six.u('TestUnicode')
input_dict = dict(cls=TestUnicode())
expected_str = '{"cls":"TestUnicode"}'
serializer = wsgi.JSONDictSerializer()
diff --git a/tools/patch_tox_venv.py b/tools/patch_tox_venv.py
new file mode 100644
index 0000000..e23cf74
--- /dev/null
+++ b/tools/patch_tox_venv.py
@@ -0,0 +1,38 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import os
+import sys
+
+import install_venv_common as install_venv
+
+
+def main(argv):
+ root = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
+
+ venv = os.environ['VIRTUAL_ENV']
+
+ pip_requires = os.path.join(root, 'tools', 'pip-requires')
+ test_requires = os.path.join(root, 'tools', 'test-requires')
+ py_version = "python%s.%s" % (sys.version_info[0], sys.version_info[1])
+ project = 'oslo'
+ install = install_venv.InstallVenv(root, venv, pip_requires, test_requires,
+ py_version, project)
+ #NOTE(dprince): For Tox we only run post_process (which patches files, etc)
+ install.post_process()
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/tox.ini b/tox.ini
index 687cf4a..cf9e11f 100644
--- a/tox.ini
+++ b/tox.ini
@@ -11,7 +11,9 @@ setenv = VIRTUAL_ENV={envdir}
NOSE_OPENSTACK_STDOUT=1
deps = -r{toxinidir}/tools/pip-requires
-r{toxinidir}/tools/test-requires
-commands = nosetests --with-doctest --exclude-dir=tests/testmods {posargs}
+commands =
+ python tools/patch_tox_venv.py
+ nosetests --with-doctest --exclude-dir=tests/testmods {posargs}
[flake8]
show-source = True
diff --git a/update.py b/update.py
index f6ffd7c..36ee3f2 100644
--- a/update.py
+++ b/update.py
@@ -173,8 +173,7 @@ def _copy_pyfile(path, base, dest_dir):
def _copy_module(mod, base, dest_dir):
- print(("Copying openstack.common.%s under the %s module in %s" %
- (mod, base, dest_dir)))
+ print("Copying %s under the %s module in %s" % (mod, base, dest_dir))
copy_pyfile = functools.partial(_copy_pyfile,
base=base, dest_dir=dest_dir)
@@ -183,7 +182,8 @@ def _copy_module(mod, base, dest_dir):
path = _mod_to_path('openstack.common')
for d in mod.split('.')[:-1]:
path = os.path.join(path, d)
- copy_pyfile(os.path.join(path, '__init__.py'))
+ if os.path.isdir(path):
+ copy_pyfile(os.path.join(path, '__init__.py'))
mod_path = _mod_to_path('openstack.common.%s' % mod)
mod_file = '%s.py' % mod_path
@@ -200,6 +200,7 @@ def _copy_module(mod, base, dest_dir):
globs_to_copy = [
os.path.join('tools', mod + '*'),
os.path.join('etc', 'oslo', mod + '*.conf'),
+ os.path.join('contrib', mod + '*'),
]
for matches in [glob.glob(g) for g in globs_to_copy]: