summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorBenjamin Peterson <benjamin@python.org>2009-10-04 14:49:41 (GMT)
committerBenjamin Peterson <benjamin@python.org>2009-10-04 14:49:41 (GMT)
commit4ac9ce4f9a33a330a555ae8015e2f2ae2780fafb (patch)
treeb9bbcfd8f4aae362d8335d13e592f605b674ea19 /Lib
parentbd27aef8a0f776cc72387be31e1e74ecbcbbdf54 (diff)
downloadcpython-4ac9ce4f9a33a330a555ae8015e2f2ae2780fafb.zip
cpython-4ac9ce4f9a33a330a555ae8015e2f2ae2780fafb.tar.gz
cpython-4ac9ce4f9a33a330a555ae8015e2f2ae2780fafb.tar.bz2
Merged revisions 74779-74786,74793,74795,74811,74860-74861,74863,74876,74886,74896,74901,74903,74908,74912,74930,74933,74943,74946,74952-74955,75015,75019,75032,75068,75076,75095,75098,75102,75129,75139,75230 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r74779 | michael.foord | 2009-09-13 11:13:36 -0500 (Sun, 13 Sep 2009) | 1 line Change to tutorial wording for reading text / binary files on Windows. Issue #6301. ........ r74780 | michael.foord | 2009-09-13 11:40:02 -0500 (Sun, 13 Sep 2009) | 1 line Objects that compare equal automatically pass or fail assertAlmostEqual and assertNotAlmostEqual tests on unittest.TestCase. Issue 6567. ........ r74781 | michael.foord | 2009-09-13 11:46:19 -0500 (Sun, 13 Sep 2009) | 1 line Note that sys._getframe is not guaranteed to exist in all implementations of Python, and a corresponding note in inspect.currentframe. Issue 6712. ........ r74782 | michael.foord | 2009-09-13 12:07:46 -0500 (Sun, 13 Sep 2009) | 1 line Tutorial tweaks. Issue 6849. ........ r74783 | michael.foord | 2009-09-13 12:28:35 -0500 (Sun, 13 Sep 2009) | 1 line unittest.TestLoader.loadTestsFromName honors the loader suiteClass attribute. Issue 6866. ........ r74784 | georg.brandl | 2009-09-13 13:15:07 -0500 (Sun, 13 Sep 2009) | 1 line Typo fix. ........ r74785 | michael.foord | 2009-09-13 14:07:03 -0500 (Sun, 13 Sep 2009) | 1 line Test discovery in unittest will only attempt to import modules that are importable; i.e. their names are valid Python identifiers. If an import fails during discovery this will be recorded as an error and test discovery will continue. Issue 6568. ........ r74786 | michael.foord | 2009-09-13 14:08:18 -0500 (Sun, 13 Sep 2009) | 1 line Remove an extraneous space in unittest documentation. ........ r74793 | georg.brandl | 2009-09-14 09:50:47 -0500 (Mon, 14 Sep 2009) | 1 line #6908: fix association of hashlib hash attributes. ........ r74795 | benjamin.peterson | 2009-09-14 22:36:26 -0500 (Mon, 14 Sep 2009) | 1 line Py_SetPythonHome uses static storage #6913 ........ r74811 | georg.brandl | 2009-09-15 15:26:59 -0500 (Tue, 15 Sep 2009) | 1 line Add Armin Ronacher. ........ r74860 | benjamin.peterson | 2009-09-16 21:46:54 -0500 (Wed, 16 Sep 2009) | 1 line kill bare except ........ r74861 | benjamin.peterson | 2009-09-16 22:18:28 -0500 (Wed, 16 Sep 2009) | 1 line pep 8 defaults ........ r74863 | benjamin.peterson | 2009-09-16 22:27:33 -0500 (Wed, 16 Sep 2009) | 1 line rationalize a bit ........ r74876 | georg.brandl | 2009-09-17 11:15:53 -0500 (Thu, 17 Sep 2009) | 1 line #6932: remove paragraph that advises relying on __del__ being called. ........ r74886 | benjamin.peterson | 2009-09-17 16:33:46 -0500 (Thu, 17 Sep 2009) | 1 line use macros ........ r74896 | georg.brandl | 2009-09-18 02:22:41 -0500 (Fri, 18 Sep 2009) | 1 line #6936: for interactive use, quit() is just fine. ........ r74901 | georg.brandl | 2009-09-18 04:14:52 -0500 (Fri, 18 Sep 2009) | 1 line #6905: use better exception messages in inspect when the argument is of the wrong type. ........ r74903 | georg.brandl | 2009-09-18 04:18:27 -0500 (Fri, 18 Sep 2009) | 1 line #6938: "ident" is always a string, so use a format code which works. ........ r74908 | georg.brandl | 2009-09-18 08:57:11 -0500 (Fri, 18 Sep 2009) | 1 line Use str.format() to fix beginner's mistake with %-style string formatting. ........ r74912 | georg.brandl | 2009-09-18 11:19:56 -0500 (Fri, 18 Sep 2009) | 1 line Optimize optimization and fix method name in docstring. ........ r74930 | georg.brandl | 2009-09-18 16:21:41 -0500 (Fri, 18 Sep 2009) | 1 line #6925: rewrite docs for locals() and vars() a bit. ........ r74933 | georg.brandl | 2009-09-18 16:35:59 -0500 (Fri, 18 Sep 2009) | 1 line #6930: clarify description about byteorder handling in UTF decoder routines. ........ r74943 | georg.brandl | 2009-09-19 02:35:07 -0500 (Sat, 19 Sep 2009) | 1 line #6944: the argument to PyArg_ParseTuple should be a tuple, otherwise a SystemError is set. Also clean up another usage of PyArg_ParseTuple. ........ r74946 | georg.brandl | 2009-09-19 03:43:16 -0500 (Sat, 19 Sep 2009) | 1 line Update bug tracker reference. ........ r74952 | georg.brandl | 2009-09-19 05:42:34 -0500 (Sat, 19 Sep 2009) | 1 line #6946: fix duplicate index entries for datetime classes. ........ r74953 | georg.brandl | 2009-09-19 07:04:16 -0500 (Sat, 19 Sep 2009) | 1 line Fix references to threading.enumerate(). ........ r74954 | georg.brandl | 2009-09-19 08:13:56 -0500 (Sat, 19 Sep 2009) | 1 line Add Doug. ........ r74955 | georg.brandl | 2009-09-19 08:20:49 -0500 (Sat, 19 Sep 2009) | 1 line Add Mark Summerfield. ........ r75015 | georg.brandl | 2009-09-22 05:55:08 -0500 (Tue, 22 Sep 2009) | 1 line Fix encoding name. ........ r75019 | vinay.sajip | 2009-09-22 12:23:41 -0500 (Tue, 22 Sep 2009) | 1 line Fixed a typo, and added sections on optimization and using arbitrary objects as messages. ........ r75032 | benjamin.peterson | 2009-09-22 17:15:28 -0500 (Tue, 22 Sep 2009) | 1 line fix typos/rephrase ........ r75068 | benjamin.peterson | 2009-09-25 21:57:59 -0500 (Fri, 25 Sep 2009) | 1 line comment out ugly xxx ........ r75076 | vinay.sajip | 2009-09-26 09:53:32 -0500 (Sat, 26 Sep 2009) | 1 line Tidied up name of parameter in StreamHandler ........ r75095 | michael.foord | 2009-09-27 14:15:41 -0500 (Sun, 27 Sep 2009) | 1 line Test creation moved from TestProgram.parseArgs to TestProgram.createTests exclusively. Issue 6956. ........ r75098 | michael.foord | 2009-09-27 15:08:23 -0500 (Sun, 27 Sep 2009) | 1 line Documentation improvement for load_tests protocol in unittest. Issue 6515. ........ r75102 | skip.montanaro | 2009-09-27 21:12:27 -0500 (Sun, 27 Sep 2009) | 3 lines Patch from Thomas Barr so that csv.Sniffer will set doublequote property. Closes issue 6606. ........ r75129 | vinay.sajip | 2009-09-29 02:08:54 -0500 (Tue, 29 Sep 2009) | 1 line Issue #7014: logging: Improved IronPython 2.6 compatibility. ........ r75139 | raymond.hettinger | 2009-09-29 13:53:24 -0500 (Tue, 29 Sep 2009) | 3 lines Issue 7008: Better document str.title and show how to work around the apostrophe problem. ........ r75230 | benjamin.peterson | 2009-10-04 08:38:38 -0500 (Sun, 04 Oct 2009) | 1 line test logging ........
Diffstat (limited to 'Lib')
-rw-r--r--Lib/csv.py22
-rw-r--r--Lib/getpass.py2
-rw-r--r--Lib/inspect.py14
-rw-r--r--Lib/logging/__init__.py30
-rw-r--r--Lib/multiprocessing/managers.py2
-rwxr-xr-xLib/platform.py2
-rw-r--r--Lib/test/test___all__.py1
-rw-r--r--Lib/test/test_csv.py9
-rw-r--r--Lib/test/test_socket.py2
-rw-r--r--Lib/test/test_unittest.py109
-rw-r--r--Lib/textwrap.py6
-rw-r--r--Lib/unittest/case.py10
-rw-r--r--Lib/unittest/loader.py63
-rw-r--r--Lib/unittest/main.py13
-rw-r--r--Lib/unittest/suite.py3
15 files changed, 203 insertions, 85 deletions
diff --git a/Lib/csv.py b/Lib/csv.py
index ee62abe..59ec372 100644
--- a/Lib/csv.py
+++ b/Lib/csv.py
@@ -165,7 +165,7 @@ class Sniffer:
Returns a dialect (or None) corresponding to the sample
"""
- quotechar, delimiter, skipinitialspace = \
+ quotechar, doublequote, delimiter, skipinitialspace = \
self._guess_quote_and_delimiter(sample, delimiters)
if not delimiter:
delimiter, skipinitialspace = self._guess_delimiter(sample,
@@ -179,8 +179,8 @@ class Sniffer:
lineterminator = '\r\n'
quoting = QUOTE_MINIMAL
# escapechar = ''
- doublequote = False
+ dialect.doublequote = doublequote
dialect.delimiter = delimiter
# _csv.reader won't accept a quotechar of ''
dialect.quotechar = quotechar or '"'
@@ -212,8 +212,8 @@ class Sniffer:
break
if not matches:
- return ('', None, 0) # (quotechar, delimiter, skipinitialspace)
-
+ # (quotechar, doublequote, delimiter, skipinitialspace)
+ return ('', False, None, 0)
quotes = {}
delims = {}
spaces = 0
@@ -248,7 +248,19 @@ class Sniffer:
delim = ''
skipinitialspace = 0
- return (quotechar, delim, skipinitialspace)
+ # if we see an extra quote between delimiters, we've got a
+ # double quoted format
+ dq_regexp = re.compile(r"((%(delim)s)|^)\W*%(quote)s[^%(delim)s\n]*%(quote)s[^%(delim)s\n]*%(quote)s\W*((%(delim)s)|$)" % \
+ {'delim':delim, 'quote':quotechar}, re.MULTILINE)
+
+
+
+ if dq_regexp.search(data):
+ doublequote = True
+ else:
+ doublequote = False
+
+ return (quotechar, doublequote, delim, skipinitialspace)
def _guess_delimiter(self, data, delimiters):
diff --git a/Lib/getpass.py b/Lib/getpass.py
index 857188f..d0030ae 100644
--- a/Lib/getpass.py
+++ b/Lib/getpass.py
@@ -51,7 +51,7 @@ def unix_getpass(prompt='Password: ', stream=None):
# If that fails, see if stdin can be controlled.
try:
fd = sys.stdin.fileno()
- except:
+ except (AttributeError, ValueError):
passwd = fallback_getpass(prompt, stream)
input = sys.stdin
if not stream:
diff --git a/Lib/inspect.py b/Lib/inspect.py
index 79565c1..1f1b7f9 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -398,12 +398,12 @@ def getfile(object):
if ismodule(object):
if hasattr(object, '__file__'):
return object.__file__
- raise TypeError('arg is a built-in module')
+ raise TypeError('{!r} is a built-in module'.format(object))
if isclass(object):
object = sys.modules.get(object.__module__)
if hasattr(object, '__file__'):
return object.__file__
- raise TypeError('arg is a built-in class')
+ raise TypeError('{!r} is a built-in class'.format(object))
if ismethod(object):
object = object.__func__
if isfunction(object):
@@ -414,8 +414,8 @@ def getfile(object):
object = object.f_code
if iscode(object):
return object.co_filename
- raise TypeError('arg is not a module, class, method, '
- 'function, traceback, frame, or code object')
+ raise TypeError('{!r} is not a module, class, method, '
+ 'function, traceback, frame, or code object'.format(object))
ModuleInfo = namedtuple('ModuleInfo', 'name suffix mode module_type')
@@ -747,7 +747,7 @@ def _getfullargs(co):
names of the * and ** arguments or None."""
if not iscode(co):
- raise TypeError('arg is not a code object')
+ raise TypeError('{!r} is not a code object'.format(co))
nargs = co.co_argcount
names = co.co_varnames
@@ -811,7 +811,7 @@ def getfullargspec(func):
if ismethod(func):
func = func.__func__
if not isfunction(func):
- raise TypeError('arg is not a Python function')
+ raise TypeError('{!r} is not a Python function'.format(func))
args, varargs, kwonlyargs, varkw = _getfullargs(func.__code__)
return FullArgSpec(args, varargs, varkw, func.__defaults__,
kwonlyargs, func.__kwdefaults__, func.__annotations__)
@@ -944,7 +944,7 @@ def getframeinfo(frame, context=1):
else:
lineno = frame.f_lineno
if not isframe(frame):
- raise TypeError('arg is not a frame or traceback object')
+ raise TypeError('{!r} is not a frame or traceback object'.format(frame))
filename = getsourcefile(frame) or getfile(frame)
if context > 0:
diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py
index 5072019..8af9e0f 100644
--- a/Lib/logging/__init__.py
+++ b/Lib/logging/__init__.py
@@ -282,11 +282,14 @@ class LogRecord:
else:
self.thread = None
self.threadName = None
- if logMultiprocessing:
- from multiprocessing import current_process
- self.processName = current_process().name
- else:
+ if not logMultiprocessing:
self.processName = None
+ else:
+ try:
+ from multiprocessing import current_process
+ self.processName = current_process().name
+ except ImportError:
+ self.processName = None
if logProcesses and hasattr(os, 'getpid'):
self.process = os.getpid()
else:
@@ -745,16 +748,16 @@ class StreamHandler(Handler):
sys.stdout or sys.stderr may be used.
"""
- def __init__(self, strm=None):
+ def __init__(self, stream=None):
"""
Initialize the handler.
- If strm is not specified, sys.stderr is used.
+ If stream is not specified, sys.stderr is used.
"""
Handler.__init__(self)
- if strm is None:
- strm = sys.stderr
- self.stream = strm
+ if stream is None:
+ stream = sys.stderr
+ self.stream = stream
def flush(self):
"""
@@ -1124,7 +1127,11 @@ class Logger(Filterer):
Find the stack frame of the caller so that we can note the source
file name, line number and function name.
"""
- f = currentframe().f_back
+ f = currentframe()
+ #On some versions of IronPython, currentframe() returns None if
+ #IronPython isn't run with -X:Frames.
+ if f is not None:
+ f = f.f_back
rv = "(unknown file)", 0, "(unknown function)"
while hasattr(f, "f_code"):
co = f.f_code
@@ -1156,7 +1163,8 @@ class Logger(Filterer):
"""
if _srcfile:
#IronPython doesn't track Python frames, so findCaller throws an
- #exception. We trap it here so that IronPython can use logging.
+ #exception on some versions of IronPython. We trap it here so that
+ #IronPython can use logging.
try:
fn, lno, func = self.findCaller()
except ValueError:
diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py
index 40af8f0..8faf34e 100644
--- a/Lib/multiprocessing/managers.py
+++ b/Lib/multiprocessing/managers.py
@@ -413,7 +413,7 @@ class Server(object):
self.id_to_refcount[ident] -= 1
if self.id_to_refcount[ident] == 0:
del self.id_to_obj[ident], self.id_to_refcount[ident]
- util.debug('disposing of obj with id %d', ident)
+ util.debug('disposing of obj with id %r', ident)
finally:
self.mutex.release()
diff --git a/Lib/platform.py b/Lib/platform.py
index 640098f..dd33f4b 100755
--- a/Lib/platform.py
+++ b/Lib/platform.py
@@ -10,7 +10,7 @@
"""
# This module is maintained by Marc-Andre Lemburg <mal@egenix.com>.
# If you find problems, please submit bug reports/patches via the
-# Python SourceForge Project Page and assign them to "lemburg".
+# Python bug tracker (http://bugs.python.org) and assign them to "lemburg".
#
# Still needed:
# * more support for WinCE
diff --git a/Lib/test/test___all__.py b/Lib/test/test___all__.py
index 8ebe568..a4e69b2 100644
--- a/Lib/test/test___all__.py
+++ b/Lib/test/test___all__.py
@@ -82,6 +82,7 @@ class AllTest(unittest.TestCase):
self.check_all("keyword")
self.check_all("linecache")
self.check_all("locale")
+ self.check_all("logging")
self.check_all("macpath")
self.check_all("macurl2path")
self.check_all("mailbox")
diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py
index 95105be..75d1a91 100644
--- a/Lib/test/test_csv.py
+++ b/Lib/test/test_csv.py
@@ -767,7 +767,7 @@ Stonecutters Seafood and Chop House, Lemont, IL, 12/19/02, Week Back
'Harry''s':'Arlington Heights':'IL':'2/1/03':'Kimi Hayes'
'Shark City':'Glendale Heights':'IL':'12/28/02':'Prezence'
'Tommy''s Place':'Blue Island':'IL':'12/28/02':'Blue Sunday/White Crow'
-'Stonecutters Seafood and Chop House':'Lemont':'IL':'12/19/02':'Week Back'
+'Stonecutters ''Seafood'' and Chop House':'Lemont':'IL':'12/19/02':'Week Back'
"""
header = '''\
"venue","city","state","date","performers"
@@ -826,6 +826,13 @@ Stonecutters Seafood and Chop House, Lemont, IL, 12/19/02, Week Back
self.assertEqual(dialect.delimiter, "|")
self.assertEqual(dialect.quotechar, "'")
+ def test_doublequote(self):
+ sniffer = csv.Sniffer()
+ dialect = sniffer.sniff(self.header)
+ self.assertFalse(dialect.doublequote)
+ dialect = sniffer.sniff(self.sample2)
+ self.assertTrue(dialect.doublequote)
+
if not hasattr(sys, "gettotalrefcount"):
if support.verbose: print("*** skipping leakage tests ***")
else:
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 1facf0a..db32335 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -291,7 +291,7 @@ class GeneralModuleTests(unittest.TestCase):
# On some versions, this loses a reference
orig = sys.getrefcount(__name__)
socket.getnameinfo(__name__,0)
- except SystemError:
+ except TypeError:
if sys.getrefcount(__name__) != orig:
self.fail("socket.getnameinfo loses a reference")
diff --git a/Lib/test/test_unittest.py b/Lib/test/test_unittest.py
index 10932de..40de797 100644
--- a/Lib/test/test_unittest.py
+++ b/Lib/test/test_unittest.py
@@ -555,6 +555,47 @@ class Test_TestLoader(TestCase):
self.assertEqual(list(suite), [testcase_1])
# "The specifier name is a ``dotted name'' that may resolve ... to
+ # ... a callable object which returns a TestCase ... instance"
+ #*****************************************************************
+ #Override the suiteClass attribute to ensure that the suiteClass
+ #attribute is used
+ def test_loadTestsFromName__callable__TestCase_instance_ProperSuiteClass(self):
+ class SubTestSuite(unittest.TestSuite):
+ pass
+ m = types.ModuleType('m')
+ testcase_1 = unittest.FunctionTestCase(lambda: None)
+ def return_TestCase():
+ return testcase_1
+ m.return_TestCase = return_TestCase
+
+ loader = unittest.TestLoader()
+ loader.suiteClass = SubTestSuite
+ suite = loader.loadTestsFromName('return_TestCase', m)
+ self.assertTrue(isinstance(suite, loader.suiteClass))
+ self.assertEqual(list(suite), [testcase_1])
+
+ # "The specifier name is a ``dotted name'' that may resolve ... to
+ # ... a test method within a test case class"
+ #*****************************************************************
+ #Override the suiteClass attribute to ensure that the suiteClass
+ #attribute is used
+ def test_loadTestsFromName__relative_testmethod_ProperSuiteClass(self):
+ class SubTestSuite(unittest.TestSuite):
+ pass
+ m = types.ModuleType('m')
+ class MyTestCase(unittest.TestCase):
+ def test(self):
+ pass
+ m.testcase_1 = MyTestCase
+
+ loader = unittest.TestLoader()
+ loader.suiteClass=SubTestSuite
+ suite = loader.loadTestsFromName('testcase_1.test', m)
+ self.assertTrue(isinstance(suite, loader.suiteClass))
+
+ self.assertEqual(list(suite), [MyTestCase('test')])
+
+ # "The specifier name is a ``dotted name'' that may resolve ... to
# ... a callable object which returns a TestCase or TestSuite instance"
#
# What happens if the callable returns something else?
@@ -2953,6 +2994,11 @@ class Test_Assertions(TestCase):
self.assertRaises(self.failureException,
self.assertNotAlmostEqual, 0, .1+.1j, places=0)
+ self.assertAlmostEqual(float('inf'), float('inf'))
+ self.assertRaises(self.failureException, self.assertNotAlmostEqual,
+ float('inf'), float('inf'))
+
+
def test_assertRaises(self):
def _raise(e):
raise e
@@ -3387,31 +3433,18 @@ class Test_TextTestRunner(TestCase):
class TestDiscovery(TestCase):
# Heavily mocked tests so I can avoid hitting the filesystem
- def test_get_module_from_path(self):
+ def test_get_name_from_path(self):
loader = unittest.TestLoader()
-
- old_import = __import__
- def restore_import():
- builtins.__import__ = old_import
- builtins.__import__ = lambda *_: None
- self.addCleanup(restore_import)
-
- expected_module = object()
- def del_module():
- del sys.modules['bar.baz']
- sys.modules['bar.baz'] = expected_module
- self.addCleanup(del_module)
-
loader._top_level_dir = '/foo'
- module = loader._get_module_from_path('/foo/bar/baz.py')
- self.assertEqual(module, expected_module)
+ name = loader._get_name_from_path('/foo/bar/baz.py')
+ self.assertEqual(name, 'bar.baz')
if not __debug__:
# asserts are off
return
with self.assertRaises(AssertionError):
- loader._get_module_from_path('/bar/baz.py')
+ loader._get_name_from_path('/bar/baz.py')
def test_find_tests(self):
loader = unittest.TestLoader()
@@ -3427,7 +3460,7 @@ class TestDiscovery(TestCase):
os.path.isdir = original_isdir
path_lists = [['test1.py', 'test2.py', 'not_a_test.py', 'test_dir',
- 'test.foo', 'another_dir'],
+ 'test.foo', 'test-not-a-module.py', 'another_dir'],
['test3.py', 'test4.py', ]]
os.listdir = lambda path: path_lists.pop(0)
self.addCleanup(restore_listdir)
@@ -3443,16 +3476,16 @@ class TestDiscovery(TestCase):
os.path.isfile = isfile
self.addCleanup(restore_isfile)
- loader._get_module_from_path = lambda path: path + ' module'
+ loader._get_module_from_name = lambda path: path + ' module'
loader.loadTestsFromModule = lambda module: module + ' tests'
loader._top_level_dir = '/foo'
suite = list(loader._find_tests('/foo', 'test*.py'))
- expected = [os.path.join('/foo', name) + ' module tests' for name in
- ('test1.py', 'test2.py')]
- expected.extend([os.path.join('/foo', 'test_dir', name) + ' module tests' for name in
- ('test3.py', 'test4.py')])
+ expected = [name + ' module tests' for name in
+ ('test1', 'test2')]
+ expected.extend([('test_dir.%s' % name) + ' module tests' for name in
+ ('test3', 'test4')])
self.assertEqual(suite, expected)
def test_find_tests_with_package(self):
@@ -3495,7 +3528,7 @@ class TestDiscovery(TestCase):
def __eq__(self, other):
return self.path == other.path
- loader._get_module_from_path = lambda path: Module(path)
+ loader._get_module_from_name = lambda name: Module(name)
def loadTestsFromModule(module, use_load_tests):
if use_load_tests:
raise self.failureException('use_load_tests should be False for packages')
@@ -3510,15 +3543,12 @@ class TestDiscovery(TestCase):
# We should have loaded tests from the test_directory package by calling load_tests
# and directly from the test_directory2 package
self.assertEqual(suite,
- ['load_tests',
- os.path.join('/foo', 'test_directory2') + ' module tests'])
- self.assertEqual(Module.paths, [os.path.join('/foo', 'test_directory'),
- os.path.join('/foo', 'test_directory2')])
+ ['load_tests', 'test_directory2' + ' module tests'])
+ self.assertEqual(Module.paths, ['test_directory', 'test_directory2'])
# load_tests should have been called once with loader, tests and pattern
self.assertEqual(Module.load_tests_args,
- [(loader, os.path.join('/foo', 'test_directory') + ' module tests',
- 'test*')])
+ [(loader, 'test_directory' + ' module tests', 'test*')])
def test_discover(self):
loader = unittest.TestLoader()
@@ -3558,6 +3588,25 @@ class TestDiscovery(TestCase):
self.assertEqual(loader._top_level_dir, top_level_dir)
self.assertEqual(_find_tests_args, [(start_dir, 'pattern')])
+ def test_discover_with_modules_that_fail_to_import(self):
+ loader = unittest.TestLoader()
+
+ listdir = os.listdir
+ os.listdir = lambda _: ['test_this_does_not_exist.py']
+ isfile = os.path.isfile
+ os.path.isfile = lambda _: True
+ def restore():
+ os.path.isfile = isfile
+ os.listdir = listdir
+ self.addCleanup(restore)
+
+ suite = loader.discover('.')
+ self.assertEqual(suite.countTestCases(), 1)
+ test = list(list(suite)[0])[0] # extract test from suite
+
+ with self.assertRaises(ImportError):
+ test.test_this_does_not_exist()
+
def test_command_line_handling_parseArgs(self):
# Haha - take that uninstantiable class
program = object.__new__(TestProgram)
diff --git a/Lib/textwrap.py b/Lib/textwrap.py
index 1f2e9b4..f4886a1 100644
--- a/Lib/textwrap.py
+++ b/Lib/textwrap.py
@@ -135,7 +135,7 @@ class TextWrapper:
"""_split(text : string) -> [string]
Split the text to wrap into indivisible chunks. Chunks are
- not quite the same as words; see wrap_chunks() for full
+ not quite the same as words; see _wrap_chunks() for full
details. As an example, the text
Look, goof-ball -- use the -b option!
breaks into the following chunks:
@@ -163,9 +163,9 @@ class TextWrapper:
space to two.
"""
i = 0
- pat = self.sentence_end_re
+ patsearch = self.sentence_end_re.search
while i < len(chunks)-1:
- if chunks[i+1] == " " and pat.search(chunks[i]):
+ if chunks[i+1] == " " and patsearch(chunks[i]):
chunks[i+1] = " "
i += 2
else:
diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py
index 48f3ef1..77ca278 100644
--- a/Lib/unittest/case.py
+++ b/Lib/unittest/case.py
@@ -468,7 +468,13 @@ class TestCase(object):
Note that decimal places (from zero) are usually not the same
as significant digits (measured from the most signficant digit).
+
+ If the two objects compare equal then they will automatically
+ compare almost equal.
"""
+ if first == second:
+ # shortcut for ite
+ return
if round(abs(second-first), places) != 0:
standardMsg = '%r != %r within %r places' % (first, second, places)
msg = self._formatMessage(msg, standardMsg)
@@ -481,8 +487,10 @@ class TestCase(object):
Note that decimal places (from zero) are usually not the same
as significant digits (measured from the most signficant digit).
+
+ Objects that are equal automatically fail.
"""
- if round(abs(second-first), places) == 0:
+ if (first == second) or round(abs(second-first), places) == 0:
standardMsg = '%r == %r within %r places' % (first, second, places)
msg = self._formatMessage(msg, standardMsg)
raise self.failureException(msg)
diff --git a/Lib/unittest/loader.py b/Lib/unittest/loader.py
index c687b1b..68f954c 100644
--- a/Lib/unittest/loader.py
+++ b/Lib/unittest/loader.py
@@ -1,7 +1,9 @@
"""Loading unittests."""
import os
+import re
import sys
+import traceback
import types
from fnmatch import fnmatch
@@ -9,6 +11,26 @@ from fnmatch import fnmatch
from . import case, suite, util
+# what about .pyc or .pyo (etc)
+# we would need to avoid loading the same tests multiple times
+# from '.py', '.pyc' *and* '.pyo'
+VALID_MODULE_NAME = re.compile(r'[_a-z]\w*\.py$', re.IGNORECASE)
+
+
+def _make_failed_import_test(name, suiteClass):
+ message = 'Failed to import test module: %s' % name
+ if hasattr(traceback, 'format_exc'):
+ # Python 2.3 compatibility
+ # format_exc returns two frames of discover.py as well
+ message += '\n%s' % traceback.format_exc()
+
+ def testImportFailure(self):
+ raise ImportError(message)
+ attrs = {name: testImportFailure}
+ ModuleImportFailure = type('ModuleImportFailure', (case.TestCase,), attrs)
+ return suiteClass((ModuleImportFailure(name),))
+
+
class TestLoader(object):
"""
This class is responsible for loading tests according to various criteria
@@ -79,7 +101,7 @@ class TestLoader(object):
inst = parent(name)
# static methods follow a different path
if not isinstance(getattr(inst, name), types.FunctionType):
- return suite.TestSuite([inst])
+ return self.suiteClass([inst])
elif isinstance(obj, suite.TestSuite):
return obj
if hasattr(obj, '__call__'):
@@ -87,7 +109,7 @@ class TestLoader(object):
if isinstance(test, suite.TestSuite):
return test
elif isinstance(test, case.TestCase):
- return suite.TestSuite([test])
+ return self.suiteClass([test])
else:
raise TypeError("calling %s returned %s, not a test" %
(obj, test))
@@ -156,17 +178,17 @@ class TestLoader(object):
tests = list(self._find_tests(start_dir, pattern))
return self.suiteClass(tests)
-
- def _get_module_from_path(self, path):
- """Load a module from a path relative to the top-level directory
- of a project. Used by discovery."""
+ def _get_name_from_path(self, path):
path = os.path.splitext(os.path.normpath(path))[0]
- relpath = os.path.relpath(path, self._top_level_dir)
- assert not os.path.isabs(relpath), "Path must be within the project"
- assert not relpath.startswith('..'), "Path must be within the project"
+ _relpath = os.path.relpath(path, self._top_level_dir)
+ assert not os.path.isabs(_relpath), "Path must be within the project"
+ assert not _relpath.startswith('..'), "Path must be within the project"
+
+ name = _relpath.replace(os.path.sep, '.')
+ return name
- name = relpath.replace(os.path.sep, '.')
+ def _get_module_from_name(self, name):
__import__(name)
return sys.modules[name]
@@ -176,14 +198,20 @@ class TestLoader(object):
for path in paths:
full_path = os.path.join(start_dir, path)
- # what about __init__.pyc or pyo (etc)
- # we would need to avoid loading the same tests multiple times
- # from '.py', '.pyc' *and* '.pyo'
- if os.path.isfile(full_path) and path.lower().endswith('.py'):
+ if os.path.isfile(full_path):
+ if not VALID_MODULE_NAME.match(path):
+ # valid Python identifiers only
+ continue
+
if fnmatch(path, pattern):
# if the test file matches, load it
- module = self._get_module_from_path(full_path)
- yield self.loadTestsFromModule(module)
+ name = self._get_name_from_path(full_path)
+ try:
+ module = self._get_module_from_name(name)
+ except:
+ yield _make_failed_import_test(name, self.suiteClass)
+ else:
+ yield self.loadTestsFromModule(module)
elif os.path.isdir(full_path):
if not os.path.isfile(os.path.join(full_path, '__init__.py')):
continue
@@ -192,7 +220,8 @@ class TestLoader(object):
tests = None
if fnmatch(path, pattern):
# only check load_tests if the package directory itself matches the filter
- package = self._get_module_from_path(full_path)
+ name = self._get_name_from_path(full_path)
+ package = self._get_module_from_name(name)
load_tests = getattr(package, 'load_tests', None)
tests = self.loadTestsFromModule(package, use_load_tests=False)
diff --git a/Lib/unittest/main.py b/Lib/unittest/main.py
index 4a5c22b..e6237b0 100644
--- a/Lib/unittest/main.py
+++ b/Lib/unittest/main.py
@@ -109,9 +109,9 @@ class TestProgram(object):
if opt in ('-v','--verbose'):
self.verbosity = 2
if len(args) == 0 and self.defaultTest is None:
- self.test = self.testLoader.loadTestsFromModule(self.module)
- return
- if len(args) > 0:
+ # createTests will load tests from self.module
+ self.testNames = None
+ elif len(args) > 0:
self.testNames = args
if __name__ == '__main__':
# to support python -m unittest ...
@@ -123,8 +123,11 @@ class TestProgram(object):
self.usageExit(msg)
def createTests(self):
- self.test = self.testLoader.loadTestsFromNames(self.testNames,
- self.module)
+ if self.testNames is None:
+ self.test = self.testLoader.loadTestsFromModule(self.module)
+ else:
+ self.test = self.testLoader.loadTestsFromNames(self.testNames,
+ self.module)
def _do_discovery(self, argv, Loader=loader.TestLoader):
# handle command line args for test discovery
diff --git a/Lib/unittest/suite.py b/Lib/unittest/suite.py
index baf8414..8672aab 100644
--- a/Lib/unittest/suite.py
+++ b/Lib/unittest/suite.py
@@ -1,6 +1,7 @@
"""TestSuite"""
from . import case
+from . import util
class TestSuite(object):
@@ -17,7 +18,7 @@ class TestSuite(object):
self.addTests(tests)
def __repr__(self):
- return "<%s tests=%s>" % (_strclass(self.__class__), list(self))
+ return "<%s tests=%s>" % (util.strclass(self.__class__), list(self))
def __eq__(self, other):
if not isinstance(other, self.__class__):