208 lines
6.9 KiB
Python
208 lines
6.9 KiB
Python
# Copyright (c) 2010-2012 extras developers. See LICENSE for details.
|
|
|
|
import sys
|
|
import types
|
|
|
|
from testtools import TestCase
|
|
from testtools.matchers import (
|
|
Equals,
|
|
Is,
|
|
Not,
|
|
)
|
|
|
|
from extras import (
|
|
safe_hasattr,
|
|
try_import,
|
|
try_imports,
|
|
)
|
|
|
|
def check_error_callback(test, function, arg, expected_error_count,
|
|
expect_result):
|
|
"""General test template for error_callback argument.
|
|
|
|
:param test: Test case instance.
|
|
:param function: Either try_import or try_imports.
|
|
:param arg: Name or names to import.
|
|
:param expected_error_count: Expected number of calls to the callback.
|
|
:param expect_result: Boolean for whether a module should
|
|
ultimately be returned or not.
|
|
"""
|
|
cb_calls = []
|
|
def cb(e):
|
|
test.assertIsInstance(e, ImportError)
|
|
cb_calls.append(e)
|
|
try:
|
|
result = function(arg, error_callback=cb)
|
|
except ImportError:
|
|
test.assertFalse(expect_result)
|
|
else:
|
|
if expect_result:
|
|
test.assertThat(result, Not(Is(None)))
|
|
else:
|
|
test.assertThat(result, Is(None))
|
|
test.assertEquals(len(cb_calls), expected_error_count)
|
|
|
|
|
|
class TestSafeHasattr(TestCase):
|
|
|
|
def test_attribute_not_there(self):
|
|
class Foo(object):
|
|
pass
|
|
self.assertEqual(False, safe_hasattr(Foo(), 'anything'))
|
|
|
|
def test_attribute_there(self):
|
|
class Foo(object):
|
|
pass
|
|
foo = Foo()
|
|
foo.attribute = None
|
|
self.assertEqual(True, safe_hasattr(foo, 'attribute'))
|
|
|
|
def test_property_there(self):
|
|
class Foo(object):
|
|
@property
|
|
def attribute(self):
|
|
return None
|
|
foo = Foo()
|
|
self.assertEqual(True, safe_hasattr(foo, 'attribute'))
|
|
|
|
def test_property_raises(self):
|
|
class Foo(object):
|
|
@property
|
|
def attribute(self):
|
|
1/0
|
|
foo = Foo()
|
|
self.assertRaises(ZeroDivisionError, safe_hasattr, foo, 'attribute')
|
|
|
|
|
|
class TestTryImport(TestCase):
|
|
|
|
def test_doesnt_exist(self):
|
|
# try_import('thing', foo) returns foo if 'thing' doesn't exist.
|
|
marker = object()
|
|
result = try_import('doesntexist', marker)
|
|
self.assertThat(result, Is(marker))
|
|
|
|
def test_None_is_default_alternative(self):
|
|
# try_import('thing') returns None if 'thing' doesn't exist.
|
|
result = try_import('doesntexist')
|
|
self.assertThat(result, Is(None))
|
|
|
|
def test_existing_module(self):
|
|
# try_import('thing', foo) imports 'thing' and returns it if it's a
|
|
# module that exists.
|
|
result = try_import('os', object())
|
|
import os
|
|
self.assertThat(result, Is(os))
|
|
|
|
def test_existing_submodule(self):
|
|
# try_import('thing.another', foo) imports 'thing' and returns it if
|
|
# it's a module that exists.
|
|
result = try_import('os.path', object())
|
|
import os
|
|
self.assertThat(result, Is(os.path))
|
|
|
|
def test_nonexistent_submodule(self):
|
|
# try_import('thing.another', foo) imports 'thing' and returns foo if
|
|
# 'another' doesn't exist.
|
|
marker = object()
|
|
result = try_import('os.doesntexist', marker)
|
|
self.assertThat(result, Is(marker))
|
|
|
|
def test_object_from_module(self):
|
|
# try_import('thing.object') imports 'thing' and returns
|
|
# 'thing.object' if 'thing' is a module and 'object' is not.
|
|
result = try_import('os.path.join')
|
|
import os
|
|
self.assertThat(result, Is(os.path.join))
|
|
|
|
def test_error_callback(self):
|
|
# the error callback is called on failures.
|
|
check_error_callback(self, try_import, 'doesntexist', 1, False)
|
|
|
|
def test_error_callback_missing_module_member(self):
|
|
# the error callback is called on failures to find an object
|
|
# inside an existing module.
|
|
check_error_callback(self, try_import, 'os.nonexistent', 1, False)
|
|
|
|
def test_error_callback_not_on_success(self):
|
|
# the error callback is not called on success.
|
|
check_error_callback(self, try_import, 'os.path', 0, True)
|
|
|
|
def test_handle_partly_imported_name(self):
|
|
# try_import('thing.other') when thing.other is mid-import
|
|
# used to fail because thing.other is not assigned until thing.other
|
|
# finishes its import - but thing.other is accessible via sys.modules.
|
|
outer = types.ModuleType("extras.outer")
|
|
inner = types.ModuleType("extras.outer.inner")
|
|
inner.attribute = object()
|
|
self.addCleanup(sys.modules.pop, "extras.outer", None)
|
|
self.addCleanup(sys.modules.pop, "extras.outer.inner", None)
|
|
sys.modules["extras.outer"] = outer
|
|
sys.modules["extras.outer.inner"] = inner
|
|
result = try_import("extras.outer.inner.attribute")
|
|
self.expectThat(result, Is(inner.attribute))
|
|
result = try_import("extras.outer.inner")
|
|
self.expectThat(result, Is(inner))
|
|
|
|
|
|
class TestTryImports(TestCase):
|
|
|
|
def test_doesnt_exist(self):
|
|
# try_imports('thing', foo) returns foo if 'thing' doesn't exist.
|
|
marker = object()
|
|
result = try_imports(['doesntexist'], marker)
|
|
self.assertThat(result, Is(marker))
|
|
|
|
def test_fallback(self):
|
|
result = try_imports(['doesntexist', 'os'])
|
|
import os
|
|
self.assertThat(result, Is(os))
|
|
|
|
def test_None_is_default_alternative(self):
|
|
# try_imports('thing') returns None if 'thing' doesn't exist.
|
|
e = self.assertRaises(
|
|
ImportError, try_imports, ['doesntexist', 'noreally'])
|
|
self.assertThat(
|
|
str(e),
|
|
Equals("Could not import any of: doesntexist, noreally"))
|
|
|
|
def test_existing_module(self):
|
|
# try_imports('thing', foo) imports 'thing' and returns it if it's a
|
|
# module that exists.
|
|
result = try_imports(['os'], object())
|
|
import os
|
|
self.assertThat(result, Is(os))
|
|
|
|
def test_existing_submodule(self):
|
|
# try_imports('thing.another', foo) imports 'thing' and returns it if
|
|
# it's a module that exists.
|
|
result = try_imports(['os.path'], object())
|
|
import os
|
|
self.assertThat(result, Is(os.path))
|
|
|
|
def test_nonexistent_submodule(self):
|
|
# try_imports('thing.another', foo) imports 'thing' and returns foo if
|
|
# 'another' doesn't exist.
|
|
marker = object()
|
|
result = try_imports(['os.doesntexist'], marker)
|
|
self.assertThat(result, Is(marker))
|
|
|
|
def test_fallback_submodule(self):
|
|
result = try_imports(['os.doesntexist', 'os.path'])
|
|
import os
|
|
self.assertThat(result, Is(os.path))
|
|
|
|
def test_error_callback(self):
|
|
# One error for every class that doesn't exist.
|
|
check_error_callback(self, try_imports,
|
|
['os.doesntexist', 'os.notthiseither'],
|
|
2, False)
|
|
check_error_callback(self, try_imports,
|
|
['os.doesntexist', 'os.notthiseither', 'os'],
|
|
2, True)
|
|
check_error_callback(self, try_imports,
|
|
['os.path'],
|
|
0, True)
|
|
|
|
|