Upgrade unittest from 3.14.2

This commit is contained in:
CPython Devleopers authored and Jeong, YunWon committed 2026-01-18 19:56:54 +09:00
1 parent 5242ff5243
commit dfed341ec8
29 files changed
+828 -181

No files matched your search

+1
View File
@@ -1,4 +1,5 @@
import os.path
from test.support import load_package_tests
+2 -1
View File
@@ -1,4 +1,5 @@
from . import load_tests
import unittest
from . import load_tests
unittest.main()
+1
View File
@@ -14,6 +14,7 @@ import sys
import unittest
import warnings
def warnfun():
warnings.warn('rw', RuntimeWarning)
+3 -2
View File
@@ -1,10 +1,11 @@
import datetime
import unittest
import warnings
import weakref
import unittest
from test.support import gc_collect
from itertools import product
from test.support import gc_collect
class Test_Assertions(unittest.TestCase):
def test_AlmostEqual(self):
+9 -3
View File
@@ -1,7 +1,9 @@
import asyncio
import contextvars
import unittest
from test import support
from test.support import force_not_colorized
support.requires_working_socket(module=True)
@@ -11,7 +13,7 @@ class MyException(Exception):
def tearDownModule():
asyncio.set_event_loop_policy(None)
asyncio.events._set_event_loop_policy(None)
class TestCM:
@@ -253,6 +255,7 @@ class TestAsyncCase(unittest.TestCase):
test.doCleanups()
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown', 'cleanup'])
@force_not_colorized
def test_exception_in_tear_clean_up(self):
class Test(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
@@ -314,18 +317,21 @@ class TestAsyncCase(unittest.TestCase):
self.assertIn('It is deprecated to return a value that is not None', str(w.warning))
self.assertIn('test1', str(w.warning))
self.assertEqual(w.filename, __file__)
self.assertIn("returned 'int'", str(w.warning))
with self.assertWarns(DeprecationWarning) as w:
Test('test2').run()
self.assertIn('It is deprecated to return a value that is not None', str(w.warning))
self.assertIn('test2', str(w.warning))
self.assertEqual(w.filename, __file__)
self.assertIn("returned 'async_generator'", str(w.warning))
with self.assertWarns(DeprecationWarning) as w:
Test('test3').run()
self.assertIn('It is deprecated to return a value that is not None', str(w.warning))
self.assertIn('test3', str(w.warning))
self.assertEqual(w.filename, __file__)
self.assertIn(f'returned {Nothing.__name__!r}', str(w.warning))
def test_cleanups_interleave_order(self):
events = []
@@ -477,7 +483,7 @@ class TestAsyncCase(unittest.TestCase):
class TestCase1(unittest.IsolatedAsyncioTestCase):
def setUp(self):
asyncio.get_event_loop_policy().get_event_loop()
asyncio.events._get_event_loop_policy().get_event_loop()
async def test_demo1(self):
pass
@@ -487,7 +493,7 @@ class TestAsyncCase(unittest.TestCase):
self.assertTrue(result.wasSuccessful())
def test_loop_factory(self):
asyncio.set_event_loop_policy(None)
asyncio.events._set_event_loop_policy(None)
class TestCase1(unittest.IsolatedAsyncioTestCase):
loop_factory = asyncio.EventLoop
+2 -2
View File
@@ -1,10 +1,10 @@
import gc
import io
import os
import sys
import signal
import weakref
import sys
import unittest
import weakref
from test import support
+349 -22
View File
@@ -1,26 +1,27 @@
import contextlib
import difflib
import pprint
import inspect
import logging
import pickle
import pprint
import re
import sys
import logging
import types
import unittest
import warnings
import weakref
import inspect
import types
from collections import UserString
from copy import deepcopy
from test import support
import unittest
from test.test_unittest.support import (
TestEquality, TestHashing, LoggingResult, LegacyLoggingResult,
ResultWithNoStartTestRunStopTestRun
)
from test.support import captured_stderr, gc_collect
from test.test_unittest.support import (
LegacyLoggingResult,
LoggingResult,
ResultWithNoStartTestRunStopTestRun,
TestEquality,
TestHashing,
)
log_foo = logging.getLogger('foo')
log_foobar = logging.getLogger('foo.bar')
@@ -54,6 +55,10 @@ class Test(object):
self.events.append('tearDown')
class List(list):
pass
class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
### Set up attributes used by inherited tests
@@ -85,7 +90,7 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
def runTest(self): raise MyException()
def test(self): pass
self.assertEqual(Test().id()[-13:], '.Test.runTest')
self.assertEndsWith(Test().id(), '.Test.runTest')
# test that TestCase can be instantiated with no args
# primarily for use at the interactive interpreter
@@ -106,7 +111,7 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
def runTest(self): raise MyException()
def test(self): pass
self.assertEqual(Test('test').id()[-10:], '.Test.test')
self.assertEndsWith(Test('test').id(), '.Test.test')
# "class TestCase([methodName])"
# ...
@@ -325,18 +330,40 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
self.assertIn('It is deprecated to return a value that is not None', str(w.warning))
self.assertIn('test1', str(w.warning))
self.assertEqual(w.filename, __file__)
self.assertIn("returned 'int'", str(w.warning))
with self.assertWarns(DeprecationWarning) as w:
Foo('test2').run()
self.assertIn('It is deprecated to return a value that is not None', str(w.warning))
self.assertIn('test2', str(w.warning))
self.assertEqual(w.filename, __file__)
self.assertIn("returned 'generator'", str(w.warning))
with self.assertWarns(DeprecationWarning) as w:
Foo('test3').run()
self.assertIn('It is deprecated to return a value that is not None', str(w.warning))
self.assertIn('test3', str(w.warning))
self.assertEqual(w.filename, __file__)
self.assertIn(f'returned {Nothing.__name__!r}', str(w.warning))
def test_deprecation_of_return_val_from_test_async_method(self):
class Foo(unittest.TestCase):
async def test1(self):
return 1
with self.assertWarns(DeprecationWarning) as w:
warnings.filterwarnings('ignore',
'coroutine .* was never awaited', RuntimeWarning)
Foo('test1').run()
support.gc_collect()
self.assertIn('It is deprecated to return a value that is not None', str(w.warning))
self.assertIn('test1', str(w.warning))
self.assertEqual(w.filename, __file__)
self.assertIn("returned 'coroutine'", str(w.warning))
self.assertIn(
'Maybe you forgot to use IsolatedAsyncioTestCase as the base class?',
str(w.warning),
)
def _check_call_order__subtests(self, result, events, expected_events):
class Foo(Test.LoggingTestCase):
@@ -678,16 +705,136 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
self.assertRaises(self.failureException, self.assertIsNot, thing, thing)
def testAssertIsInstance(self):
thing = []
thing = List()
self.assertIsInstance(thing, list)
self.assertRaises(self.failureException, self.assertIsInstance,
thing, dict)
self.assertIsInstance(thing, (int, list))
with self.assertRaises(self.failureException) as cm:
self.assertIsInstance(thing, int)
self.assertEqual(str(cm.exception),
"[] is not an instance of <class 'int'>")
with self.assertRaises(self.failureException) as cm:
self.assertIsInstance(thing, (int, float))
self.assertEqual(str(cm.exception),
"[] is not an instance of any of (<class 'int'>, <class 'float'>)")
with self.assertRaises(self.failureException) as cm:
self.assertIsInstance(thing, int, 'ababahalamaha')
self.assertIn('ababahalamaha', str(cm.exception))
with self.assertRaises(self.failureException) as cm:
self.assertIsInstance(thing, int, msg='ababahalamaha')
self.assertIn('ababahalamaha', str(cm.exception))
def testAssertNotIsInstance(self):
thing = []
self.assertNotIsInstance(thing, dict)
self.assertRaises(self.failureException, self.assertNotIsInstance,
thing, list)
thing = List()
self.assertNotIsInstance(thing, int)
self.assertNotIsInstance(thing, (int, float))
with self.assertRaises(self.failureException) as cm:
self.assertNotIsInstance(thing, list)
self.assertEqual(str(cm.exception),
"[] is an instance of <class 'list'>")
with self.assertRaises(self.failureException) as cm:
self.assertNotIsInstance(thing, (int, list))
self.assertEqual(str(cm.exception),
"[] is an instance of <class 'list'>")
with self.assertRaises(self.failureException) as cm:
self.assertNotIsInstance(thing, list, 'ababahalamaha')
self.assertIn('ababahalamaha', str(cm.exception))
with self.assertRaises(self.failureException) as cm:
self.assertNotIsInstance(thing, list, msg='ababahalamaha')
self.assertIn('ababahalamaha', str(cm.exception))
def testAssertIsSubclass(self):
self.assertIsSubclass(List, list)
self.assertIsSubclass(List, (int, list))
with self.assertRaises(self.failureException) as cm:
self.assertIsSubclass(List, int)
self.assertEqual(str(cm.exception),
f"{List!r} is not a subclass of <class 'int'>")
with self.assertRaises(self.failureException) as cm:
self.assertIsSubclass(List, (int, float))
self.assertEqual(str(cm.exception),
f"{List!r} is not a subclass of any of (<class 'int'>, <class 'float'>)")
with self.assertRaises(self.failureException) as cm:
self.assertIsSubclass(1, int)
self.assertEqual(str(cm.exception), "1 is not a class")
with self.assertRaises(self.failureException) as cm:
self.assertIsSubclass(List, int, 'ababahalamaha')
self.assertIn('ababahalamaha', str(cm.exception))
with self.assertRaises(self.failureException) as cm:
self.assertIsSubclass(List, int, msg='ababahalamaha')
self.assertIn('ababahalamaha', str(cm.exception))
def testAssertNotIsSubclass(self):
self.assertNotIsSubclass(List, int)
self.assertNotIsSubclass(List, (int, float))
with self.assertRaises(self.failureException) as cm:
self.assertNotIsSubclass(List, list)
self.assertEqual(str(cm.exception),
f"{List!r} is a subclass of <class 'list'>")
with self.assertRaises(self.failureException) as cm:
self.assertNotIsSubclass(List, (int, list))
self.assertEqual(str(cm.exception),
f"{List!r} is a subclass of <class 'list'>")
with self.assertRaises(self.failureException) as cm:
self.assertNotIsSubclass(1, int)
self.assertEqual(str(cm.exception), "1 is not a class")
with self.assertRaises(self.failureException) as cm:
self.assertNotIsSubclass(List, list, 'ababahalamaha')
self.assertIn('ababahalamaha', str(cm.exception))
with self.assertRaises(self.failureException) as cm:
self.assertNotIsSubclass(List, list, msg='ababahalamaha')
self.assertIn('ababahalamaha', str(cm.exception))
def testAssertHasAttr(self):
a = List()
a.x = 1
self.assertHasAttr(a, 'x')
with self.assertRaises(self.failureException) as cm:
self.assertHasAttr(a, 'y')
self.assertEqual(str(cm.exception),
"'List' object has no attribute 'y'")
with self.assertRaises(self.failureException) as cm:
self.assertHasAttr(List, 'spam')
self.assertEqual(str(cm.exception),
"type object 'List' has no attribute 'spam'")
with self.assertRaises(self.failureException) as cm:
self.assertHasAttr(sys, 'nonexistent')
self.assertEqual(str(cm.exception),
"module 'sys' has no attribute 'nonexistent'")
with self.assertRaises(self.failureException) as cm:
self.assertHasAttr(a, 'y', 'ababahalamaha')
self.assertIn('ababahalamaha', str(cm.exception))
with self.assertRaises(self.failureException) as cm:
self.assertHasAttr(a, 'y', msg='ababahalamaha')
self.assertIn('ababahalamaha', str(cm.exception))
def testAssertNotHasAttr(self):
a = List()
a.x = 1
self.assertNotHasAttr(a, 'y')
with self.assertRaises(self.failureException) as cm:
self.assertNotHasAttr(a, 'x')
self.assertEqual(str(cm.exception),
"'List' object has unexpected attribute 'x'")
with self.assertRaises(self.failureException) as cm:
self.assertNotHasAttr(List, 'append')
self.assertEqual(str(cm.exception),
"type object 'List' has unexpected attribute 'append'")
with self.assertRaises(self.failureException) as cm:
self.assertNotHasAttr(sys, 'modules')
self.assertEqual(str(cm.exception),
"module 'sys' has unexpected attribute 'modules'")
with self.assertRaises(self.failureException) as cm:
self.assertNotHasAttr(a, 'x', 'ababahalamaha')
self.assertIn('ababahalamaha', str(cm.exception))
with self.assertRaises(self.failureException) as cm:
self.assertNotHasAttr(a, 'x', msg='ababahalamaha')
self.assertIn('ababahalamaha', str(cm.exception))
def testAssertIn(self):
animals = {'monkey': 'banana', 'cow': 'grass', 'seal': 'fish'}
@@ -1842,6 +1989,186 @@ test case
pass
self.assertIsNone(value)
def testAssertStartsWith(self):
self.assertStartsWith('ababahalamaha', 'ababa')
self.assertStartsWith('ababahalamaha', ('x', 'ababa', 'y'))
self.assertStartsWith(UserString('ababahalamaha'), 'ababa')
self.assertStartsWith(UserString('ababahalamaha'), ('x', 'ababa', 'y'))
self.assertStartsWith(bytearray(b'ababahalamaha'), b'ababa')
self.assertStartsWith(bytearray(b'ababahalamaha'), (b'x', b'ababa', b'y'))
self.assertStartsWith(b'ababahalamaha', bytearray(b'ababa'))
self.assertStartsWith(b'ababahalamaha',
(bytearray(b'x'), bytearray(b'ababa'), bytearray(b'y')))
with self.assertRaises(self.failureException) as cm:
self.assertStartsWith('ababahalamaha', 'amaha')
self.assertEqual(str(cm.exception),
"'ababahalamaha' doesn't start with 'amaha'")
with self.assertRaises(self.failureException) as cm:
self.assertStartsWith('ababahalamaha', ('x', 'y'))
self.assertEqual(str(cm.exception),
"'ababahalamaha' doesn't start with any of ('x', 'y')")
with self.assertRaises(self.failureException) as cm:
self.assertStartsWith(b'ababahalamaha', 'ababa')
self.assertEqual(str(cm.exception), 'Expected str, not bytes')
with self.assertRaises(self.failureException) as cm:
self.assertStartsWith(b'ababahalamaha', ('amaha', 'ababa'))
self.assertEqual(str(cm.exception), 'Expected str, not bytes')
with self.assertRaises(self.failureException) as cm:
self.assertStartsWith([], 'ababa')
self.assertEqual(str(cm.exception), 'Expected str, not list')
with self.assertRaises(self.failureException) as cm:
self.assertStartsWith('ababahalamaha', b'ababa')
self.assertEqual(str(cm.exception), 'Expected bytes, not str')
with self.assertRaises(self.failureException) as cm:
self.assertStartsWith('ababahalamaha', (b'amaha', b'ababa'))
self.assertEqual(str(cm.exception), 'Expected bytes, not str')
with self.assertRaises(TypeError):
self.assertStartsWith('ababahalamaha', ord('a'))
with self.assertRaises(self.failureException) as cm:
self.assertStartsWith('ababahalamaha', 'amaha', 'abracadabra')
self.assertIn('ababahalamaha', str(cm.exception))
with self.assertRaises(self.failureException) as cm:
self.assertStartsWith('ababahalamaha', 'amaha', msg='abracadabra')
self.assertIn('ababahalamaha', str(cm.exception))
def testAssertNotStartsWith(self):
self.assertNotStartsWith('ababahalamaha', 'amaha')
self.assertNotStartsWith('ababahalamaha', ('x', 'amaha', 'y'))
self.assertNotStartsWith(UserString('ababahalamaha'), 'amaha')
self.assertNotStartsWith(UserString('ababahalamaha'), ('x', 'amaha', 'y'))
self.assertNotStartsWith(bytearray(b'ababahalamaha'), b'amaha')
self.assertNotStartsWith(bytearray(b'ababahalamaha'), (b'x', b'amaha', b'y'))
self.assertNotStartsWith(b'ababahalamaha', bytearray(b'amaha'))
self.assertNotStartsWith(b'ababahalamaha',
(bytearray(b'x'), bytearray(b'amaha'), bytearray(b'y')))
with self.assertRaises(self.failureException) as cm:
self.assertNotStartsWith('ababahalamaha', 'ababa')
self.assertEqual(str(cm.exception),
"'ababahalamaha' starts with 'ababa'")
with self.assertRaises(self.failureException) as cm:
self.assertNotStartsWith('ababahalamaha', ('x', 'ababa', 'y'))
self.assertEqual(str(cm.exception),
"'ababahalamaha' starts with 'ababa'")
with self.assertRaises(self.failureException) as cm:
self.assertNotStartsWith(b'ababahalamaha', 'ababa')
self.assertEqual(str(cm.exception), 'Expected str, not bytes')
with self.assertRaises(self.failureException) as cm:
self.assertNotStartsWith(b'ababahalamaha', ('amaha', 'ababa'))
self.assertEqual(str(cm.exception), 'Expected str, not bytes')
with self.assertRaises(self.failureException) as cm:
self.assertNotStartsWith([], 'ababa')
self.assertEqual(str(cm.exception), 'Expected str, not list')
with self.assertRaises(self.failureException) as cm:
self.assertNotStartsWith('ababahalamaha', b'ababa')
self.assertEqual(str(cm.exception), 'Expected bytes, not str')
with self.assertRaises(self.failureException) as cm:
self.assertNotStartsWith('ababahalamaha', (b'amaha', b'ababa'))
self.assertEqual(str(cm.exception), 'Expected bytes, not str')
with self.assertRaises(TypeError):
self.assertNotStartsWith('ababahalamaha', ord('a'))
with self.assertRaises(self.failureException) as cm:
self.assertNotStartsWith('ababahalamaha', 'ababa', 'abracadabra')
self.assertIn('ababahalamaha', str(cm.exception))
with self.assertRaises(self.failureException) as cm:
self.assertNotStartsWith('ababahalamaha', 'ababa', msg='abracadabra')
self.assertIn('ababahalamaha', str(cm.exception))
def testAssertEndsWith(self):
self.assertEndsWith('ababahalamaha', 'amaha')
self.assertEndsWith('ababahalamaha', ('x', 'amaha', 'y'))
self.assertEndsWith(UserString('ababahalamaha'), 'amaha')
self.assertEndsWith(UserString('ababahalamaha'), ('x', 'amaha', 'y'))
self.assertEndsWith(bytearray(b'ababahalamaha'), b'amaha')
self.assertEndsWith(bytearray(b'ababahalamaha'), (b'x', b'amaha', b'y'))
self.assertEndsWith(b'ababahalamaha', bytearray(b'amaha'))
self.assertEndsWith(b'ababahalamaha',
(bytearray(b'x'), bytearray(b'amaha'), bytearray(b'y')))
with self.assertRaises(self.failureException) as cm:
self.assertEndsWith('ababahalamaha', 'ababa')
self.assertEqual(str(cm.exception),
"'ababahalamaha' doesn't end with 'ababa'")
with self.assertRaises(self.failureException) as cm:
self.assertEndsWith('ababahalamaha', ('x', 'y'))
self.assertEqual(str(cm.exception),
"'ababahalamaha' doesn't end with any of ('x', 'y')")
with self.assertRaises(self.failureException) as cm:
self.assertEndsWith(b'ababahalamaha', 'amaha')
self.assertEqual(str(cm.exception), 'Expected str, not bytes')
with self.assertRaises(self.failureException) as cm:
self.assertEndsWith(b'ababahalamaha', ('ababa', 'amaha'))
self.assertEqual(str(cm.exception), 'Expected str, not bytes')
with self.assertRaises(self.failureException) as cm:
self.assertEndsWith([], 'amaha')
self.assertEqual(str(cm.exception), 'Expected str, not list')
with self.assertRaises(self.failureException) as cm:
self.assertEndsWith('ababahalamaha', b'amaha')
self.assertEqual(str(cm.exception), 'Expected bytes, not str')
with self.assertRaises(self.failureException) as cm:
self.assertEndsWith('ababahalamaha', (b'ababa', b'amaha'))
self.assertEqual(str(cm.exception), 'Expected bytes, not str')
with self.assertRaises(TypeError):
self.assertEndsWith('ababahalamaha', ord('a'))
with self.assertRaises(self.failureException) as cm:
self.assertEndsWith('ababahalamaha', 'ababa', 'abracadabra')
self.assertIn('ababahalamaha', str(cm.exception))
with self.assertRaises(self.failureException) as cm:
self.assertEndsWith('ababahalamaha', 'ababa', msg='abracadabra')
self.assertIn('ababahalamaha', str(cm.exception))
def testAssertNotEndsWith(self):
self.assertNotEndsWith('ababahalamaha', 'ababa')
self.assertNotEndsWith('ababahalamaha', ('x', 'ababa', 'y'))
self.assertNotEndsWith(UserString('ababahalamaha'), 'ababa')
self.assertNotEndsWith(UserString('ababahalamaha'), ('x', 'ababa', 'y'))
self.assertNotEndsWith(bytearray(b'ababahalamaha'), b'ababa')
self.assertNotEndsWith(bytearray(b'ababahalamaha'), (b'x', b'ababa', b'y'))
self.assertNotEndsWith(b'ababahalamaha', bytearray(b'ababa'))
self.assertNotEndsWith(b'ababahalamaha',
(bytearray(b'x'), bytearray(b'ababa'), bytearray(b'y')))
with self.assertRaises(self.failureException) as cm:
self.assertNotEndsWith('ababahalamaha', 'amaha')
self.assertEqual(str(cm.exception),
"'ababahalamaha' ends with 'amaha'")
with self.assertRaises(self.failureException) as cm:
self.assertNotEndsWith('ababahalamaha', ('x', 'amaha', 'y'))
self.assertEqual(str(cm.exception),
"'ababahalamaha' ends with 'amaha'")
with self.assertRaises(self.failureException) as cm:
self.assertNotEndsWith(b'ababahalamaha', 'amaha')
self.assertEqual(str(cm.exception), 'Expected str, not bytes')
with self.assertRaises(self.failureException) as cm:
self.assertNotEndsWith(b'ababahalamaha', ('ababa', 'amaha'))
self.assertEqual(str(cm.exception), 'Expected str, not bytes')
with self.assertRaises(self.failureException) as cm:
self.assertNotEndsWith([], 'amaha')
self.assertEqual(str(cm.exception), 'Expected str, not list')
with self.assertRaises(self.failureException) as cm:
self.assertNotEndsWith('ababahalamaha', b'amaha')
self.assertEqual(str(cm.exception), 'Expected bytes, not str')
with self.assertRaises(self.failureException) as cm:
self.assertNotEndsWith('ababahalamaha', (b'ababa', b'amaha'))
self.assertEqual(str(cm.exception), 'Expected bytes, not str')
with self.assertRaises(TypeError):
self.assertNotEndsWith('ababahalamaha', ord('a'))
with self.assertRaises(self.failureException) as cm:
self.assertNotEndsWith('ababahalamaha', 'amaha', 'abracadabra')
self.assertIn('ababahalamaha', str(cm.exception))
with self.assertRaises(self.failureException) as cm:
self.assertNotEndsWith('ababahalamaha', 'amaha', msg='abracadabra')
self.assertIn('ababahalamaha', str(cm.exception))
def testDeprecatedFailMethods(self):
"""Test that the deprecated fail* methods get removed in 3.12"""
deprecated_names = [
+57 -7
View File
@@ -1,15 +1,17 @@
import os.path
from os.path import abspath
import pickle
import re
import sys
import types
import pickle
from test import support
from test.support import import_helper
import unittest
import unittest.mock
from importlib._bootstrap_external import NamespaceLoader
from os.path import abspath
import test.test_unittest
from test import support
from test.support import import_helper
from test.test_importlib import util as test_util
class TestableTestProgram(unittest.TestProgram):
@@ -395,7 +397,7 @@ class TestDiscovery(unittest.TestCase):
self.addCleanup(restore_isdir)
_find_tests_args = []
def _find_tests(start_dir, pattern):
def _find_tests(start_dir, pattern, namespace=None):
_find_tests_args.append((start_dir, pattern))
return ['tests']
loader._find_tests = _find_tests
@@ -815,7 +817,7 @@ class TestDiscovery(unittest.TestCase):
expectedPath = os.path.abspath(os.path.dirname(test.test_unittest.__file__))
self.wasRun = False
def _find_tests(start_dir, pattern):
def _find_tests(start_dir, pattern, namespace=None):
self.wasRun = True
self.assertEqual(start_dir, expectedPath)
return tests
@@ -848,6 +850,54 @@ class TestDiscovery(unittest.TestCase):
'Can not use builtin modules '
'as dotted module names')
def test_discovery_from_dotted_namespace_packages(self):
loader = unittest.TestLoader()
package = types.ModuleType('package')
package.__name__ = "tests"
package.__path__ = ['/a', '/b']
package.__file__ = None
package.__spec__ = types.SimpleNamespace(
name=package.__name__,
loader=NamespaceLoader(package.__name__, package.__path__, None),
submodule_search_locations=['/a', '/b']
)
def _import(packagename, *args, **kwargs):
sys.modules[packagename] = package
return package
_find_tests_args = []
def _find_tests(start_dir, pattern, namespace=None):
_find_tests_args.append((start_dir, pattern))
return ['%s/tests' % start_dir]
loader._find_tests = _find_tests
loader.suiteClass = list
with unittest.mock.patch('builtins.__import__', _import):
# Since loader.discover() can modify sys.path, restore it when done.
with import_helper.DirsOnSysPath():
# Make sure to remove 'package' from sys.modules when done.
with test_util.uncache('package'):
suite = loader.discover('package')
self.assertEqual(suite, ['/a/tests', '/b/tests'])
def test_discovery_start_dir_is_namespace(self):
"""Subdirectory discovery not affected if start_dir is a namespace pkg."""
loader = unittest.TestLoader()
with (
import_helper.DirsOnSysPath(os.path.join(os.path.dirname(__file__))),
test_util.uncache('namespace_test_pkg')
):
suite = loader.discover('namespace_test_pkg')
self.assertEqual(
{list(suite)[0]._tests[0].__module__ for suite in suite._tests if list(suite)},
# files under namespace_test_pkg.noop not discovered.
{'namespace_test_pkg.test_foo', 'namespace_test_pkg.bar.test_bar'},
)
def test_discovery_failed_discovery(self):
from test.test_importlib import util
+2 -2
View File
@@ -1,9 +1,9 @@
import functools
import sys
import types
import unittest
class Test_TestLoader(unittest.TestCase):
### Basic object tests
@@ -76,7 +76,7 @@ class Test_TestLoader(unittest.TestCase):
loader = unittest.TestLoader()
# This has to be false for the test to succeed
self.assertFalse('runTest'.startswith(loader.testMethodPrefix))
self.assertNotStartsWith('runTest', loader.testMethodPrefix)
suite = loader.loadTestsFromTestCase(Foo)
self.assertIsInstance(suite, loader.suiteClass)
+8 -8
View File
@@ -1,9 +1,10 @@
import os
import sys
import subprocess
from test import support
import sys
import unittest
import test.test_unittest
from test import support
from test.test_unittest.test_result import BufferedWriter
@@ -135,14 +136,14 @@ class Test_TestProgram(unittest.TestCase):
argv=["foobar"],
testRunner=unittest.TextTestRunner(stream=stream),
testLoader=self.TestLoader(self.FooBar))
self.assertTrue(hasattr(program, 'result'))
self.assertHasAttr(program, 'result')
out = stream.getvalue()
self.assertIn('\nFAIL: testFail ', out)
self.assertIn('\nERROR: testError ', out)
self.assertIn('\nUNEXPECTED SUCCESS: testUnexpectedSuccess ', out)
expected = ('\n\nFAILED (failures=1, errors=1, skipped=1, '
'expected failures=1, unexpected successes=1)\n')
self.assertTrue(out.endswith(expected))
self.assertEndsWith(out, expected)
def test_Exit(self):
stream = BufferedWriter()
@@ -159,7 +160,7 @@ class Test_TestProgram(unittest.TestCase):
self.assertIn('\nUNEXPECTED SUCCESS: testUnexpectedSuccess ', out)
expected = ('\n\nFAILED (failures=1, errors=1, skipped=1, '
'expected failures=1, unexpected successes=1)\n')
self.assertTrue(out.endswith(expected))
self.assertEndsWith(out, expected)
def test_ExitAsDefault(self):
stream = BufferedWriter()
@@ -174,7 +175,7 @@ class Test_TestProgram(unittest.TestCase):
self.assertIn('\nUNEXPECTED SUCCESS: testUnexpectedSuccess ', out)
expected = ('\n\nFAILED (failures=1, errors=1, skipped=1, '
'expected failures=1, unexpected successes=1)\n')
self.assertTrue(out.endswith(expected))
self.assertEndsWith(out, expected)
def test_ExitSkippedSuite(self):
stream = BufferedWriter()
@@ -186,7 +187,7 @@ class Test_TestProgram(unittest.TestCase):
self.assertEqual(cm.exception.code, 0)
out = stream.getvalue()
expected = '\n\nOK (skipped=1)\n'
self.assertTrue(out.endswith(expected))
self.assertEndsWith(out, expected)
def test_ExitEmptySuite(self):
stream = BufferedWriter()
@@ -506,7 +507,6 @@ class TestCommandLineArgs(unittest.TestCase):
self.assertEqual(program.testNamePatterns, ['*foo*', '*bar*', '*pat*'])
@unittest.expectedFailureIf(sys.platform != 'win32', 'TODO: RUSTPYTHON')
def testSelectedTestNamesFunctionalTest(self):
def run_unittest(args):
# Use -E to ignore PYTHONSAFEPATH env var
+15 -11
View File
@@ -4,8 +4,12 @@ import textwrap
import traceback
import unittest
from unittest.util import strclass
from test.support import warnings_helper
from test.support import captured_stdout, force_not_colorized_test_class
from test.support import (
captured_stdout,
force_not_colorized_test_class,
warnings_helper,
)
from test.test_unittest.support import BufferedWriter
@@ -13,7 +17,7 @@ class MockTraceback(object):
class TracebackException:
def __init__(self, *args, **kwargs):
self.capture_locals = kwargs.get('capture_locals', False)
def format(self):
def format(self, **kwargs):
result = ['A traceback']
if self.capture_locals:
result.append('locals')
@@ -186,7 +190,7 @@ class Test_TestResult(unittest.TestCase):
test = Foo('test_1')
try:
test.fail("foo")
except:
except AssertionError:
exc_info_tuple = sys.exc_info()
result = unittest.TestResult()
@@ -214,7 +218,7 @@ class Test_TestResult(unittest.TestCase):
def get_exc_info():
try:
test.fail("foo")
except:
except AssertionError:
return sys.exc_info()
exc_info_tuple = get_exc_info()
@@ -241,9 +245,9 @@ class Test_TestResult(unittest.TestCase):
try:
try:
test.fail("foo")
except:
except AssertionError:
raise ValueError(42)
except:
except ValueError:
return sys.exc_info()
exc_info_tuple = get_exc_info()
@@ -271,7 +275,7 @@ class Test_TestResult(unittest.TestCase):
loop.__cause__ = loop
loop.__context__ = loop
raise loop
except:
except Exception:
return sys.exc_info()
exc_info_tuple = get_exc_info()
@@ -300,7 +304,7 @@ class Test_TestResult(unittest.TestCase):
ex1.__cause__ = ex2
ex2.__context__ = ex1
raise C
except:
except Exception:
return sys.exc_info()
exc_info_tuple = get_exc_info()
@@ -345,7 +349,7 @@ class Test_TestResult(unittest.TestCase):
test = Foo('test_1')
try:
raise TypeError()
except:
except TypeError:
exc_info_tuple = sys.exc_info()
result = unittest.TestResult()
@@ -454,7 +458,7 @@ class Test_TestResult(unittest.TestCase):
self.assertTrue(result.failfast)
result = runner.run(test)
stream.flush()
self.assertTrue(stream.getvalue().endswith('\n\nOK\n'))
self.assertEndsWith(stream.getvalue(), '\n\nOK\n')
@force_not_colorized_test_class
+2 -3
View File
@@ -1,13 +1,12 @@
import io
import os
import sys
import pickle
import subprocess
from test import support
import sys
import unittest
from unittest.case import _Outcome
from test import support
from test.test_unittest.support import (
BufferedWriter,
LoggingResult,
-1
View File
@@ -1,6 +1,5 @@
import io
import sys
import unittest
+3
View File
@@ -1,5 +1,6 @@
import unittest
from test.support import force_not_colorized
from test.test_unittest.support import LoggingResult
@@ -293,6 +294,7 @@ class Test_TestSkipping(unittest.TestCase):
self.assertFalse(result.unexpectedSuccesses)
self.assertTrue(result.wasSuccessful())
@force_not_colorized
def test_expected_failure_and_fail_in_cleanup(self):
class Foo(unittest.TestCase):
@unittest.expectedFailure
@@ -372,6 +374,7 @@ class Test_TestSkipping(unittest.TestCase):
self.assertEqual(result.unexpectedSuccesses, [test])
self.assertFalse(result.wasSuccessful())
@force_not_colorized
def test_unexpected_success_and_fail_in_cleanup(self):
class Foo(unittest.TestCase):
@unittest.expectedFailure
+2 -3
View File
@@ -1,10 +1,9 @@
import unittest
import gc
import sys
import unittest
import weakref
from test.test_unittest.support import LoggingResult, TestEquality
from test.test_unittest.support import LoggingResult, TestEquality
### Support code for Test_TestSuite
################################################################
+5 -1
View File
@@ -1,5 +1,9 @@
import unittest
from unittest.util import safe_repr, sorted_list_difference, unorderable_list_difference
from unittest.util import (
safe_repr,
sorted_list_difference,
unorderable_list_difference,
)
class TestUtil(unittest.TestCase):
+24 -9
View File
@@ -27,7 +27,7 @@ Further information is available in the bundled documentation, and from
http://docs.python.org/library/unittest.html
Copyright (c) 1999-2003 Steve Purcell
Copyright (c) 2003-2010 Python Software Foundation
Copyright (c) 2003 Python Software Foundation
This module is free software, and you may redistribute it and/or modify
it under the same terms as Python itself, so long as this copyright message
and disclaimer are retained in their original form.
@@ -53,15 +53,30 @@ __all__ = ['TestResult', 'TestCase', 'IsolatedAsyncioTestCase', 'TestSuite',
__unittest = True
from .result import TestResult
from .case import (addModuleCleanup, TestCase, FunctionTestCase, SkipTest, skip,
skipIf, skipUnless, expectedFailure, doModuleCleanups,
enterModuleContext)
from .suite import BaseTestSuite, TestSuite
from .case import (
FunctionTestCase,
SkipTest,
TestCase,
addModuleCleanup,
doModuleCleanups,
enterModuleContext,
expectedFailure,
skip,
skipIf,
skipUnless,
)
from .loader import TestLoader, defaultTestLoader
from .main import TestProgram, main
from .runner import TextTestRunner, TextTestResult
from .signals import installHandler, registerResult, removeResult, removeHandler
from .main import TestProgram, main # noqa: F401
from .result import TestResult
from .runner import TextTestResult, TextTestRunner
from .signals import (
installHandler,
registerResult,
removeHandler,
removeResult,
)
from .suite import BaseTestSuite, TestSuite # noqa: F401
# IsolatedAsyncioTestCase will be imported lazily.
+1
View File
@@ -1,6 +1,7 @@
"""Main entry point"""
import sys
if sys.argv[0].endswith("__main__.py"):
import os.path
# We change sys.argv[0] to make help message more useful
+1 -2
View File
@@ -1,9 +1,8 @@
import logging
import collections
import logging
from .case import _BaseTestCaseContext
_LoggingWatcher = collections.namedtuple("_LoggingWatcher",
["records", "output"])
+18 -6
View File
@@ -75,9 +75,17 @@ class IsolatedAsyncioTestCase(TestCase):
enter = cls.__aenter__
exit = cls.__aexit__
except AttributeError:
raise TypeError(f"'{cls.__module__}.{cls.__qualname__}' object does "
f"not support the asynchronous context manager protocol"
) from None
msg = (f"'{cls.__module__}.{cls.__qualname__}' object does "
"not support the asynchronous context manager protocol")
try:
cls.__enter__
cls.__exit__
except AttributeError:
pass
else:
msg += (" but it supports the context manager protocol. "
"Did you mean to use enterContext()?")
raise TypeError(msg) from None
result = await enter(cm)
self.addAsyncCleanup(exit, cm, None, None, None)
return result
@@ -91,9 +99,13 @@ class IsolatedAsyncioTestCase(TestCase):
self._callAsync(self.asyncSetUp)
def _callTestMethod(self, method):
if self._callMaybeAsync(method) is not None:
warnings.warn(f'It is deprecated to return a value that is not None from a '
f'test case ({method})', DeprecationWarning, stacklevel=4)
result = self._callMaybeAsync(method)
if result is not None:
msg = (
f'It is deprecated to return a value that is not None '
f'from a test case ({method} returned {type(result).__name__!r})',
)
warnings.warn(msg, DeprecationWarning, stacklevel=4)
def _callTearDown(self):
self._callAsync(self.asyncTearDown)
+171 -16
View File
@@ -1,20 +1,25 @@
"""Test case implementation"""
import sys
import functools
import difflib
import pprint
import re
import warnings
import collections
import contextlib
import traceback
import difflib
import functools
import pprint
import re
import sys
import time
import traceback
import types
import warnings
from . import result
from .util import (strclass, safe_repr, _count_diff_all_purpose,
_count_diff_hashable, _common_shorten_repr)
from .util import (
_common_shorten_repr,
_count_diff_all_purpose,
_count_diff_hashable,
safe_repr,
strclass,
)
__unittest = True
@@ -111,8 +116,17 @@ def _enter_context(cm, addcleanup):
enter = cls.__enter__
exit = cls.__exit__
except AttributeError:
raise TypeError(f"'{cls.__module__}.{cls.__qualname__}' object does "
f"not support the context manager protocol") from None
msg = (f"'{cls.__module__}.{cls.__qualname__}' object does "
"not support the context manager protocol")
try:
cls.__aenter__
cls.__aexit__
except AttributeError:
pass
else:
msg += (" but it supports the asynchronous context manager "
"protocol. Did you mean to use enterAsyncContext()?")
raise TypeError(msg) from None
result = enter(cm)
addcleanup(exit, cm, None, None, None)
return result
@@ -603,9 +617,18 @@ class TestCase(object):
self.setUp()
def _callTestMethod(self, method):
if method() is not None:
warnings.warn(f'It is deprecated to return a value that is not None from a '
f'test case ({method})', DeprecationWarning, stacklevel=3)
result = method()
if result is not None:
import inspect
msg = (
f'It is deprecated to return a value that is not None '
f'from a test case ({method} returned {type(result).__name__!r})'
)
if inspect.iscoroutine(result):
msg += (
'. Maybe you forgot to use IsolatedAsyncioTestCase as the base class?'
)
warnings.warn(msg, DeprecationWarning, stacklevel=3)
def _callTearDown(self):
self.tearDown()
@@ -1312,13 +1335,71 @@ class TestCase(object):
"""Same as self.assertTrue(isinstance(obj, cls)), with a nicer
default message."""
if not isinstance(obj, cls):
standardMsg = '%s is not an instance of %r' % (safe_repr(obj), cls)
if isinstance(cls, tuple):
standardMsg = f'{safe_repr(obj)} is not an instance of any of {cls!r}'
else:
standardMsg = f'{safe_repr(obj)} is not an instance of {cls!r}'
self.fail(self._formatMessage(msg, standardMsg))
def assertNotIsInstance(self, obj, cls, msg=None):
"""Included for symmetry with assertIsInstance."""
if isinstance(obj, cls):
standardMsg = '%s is an instance of %r' % (safe_repr(obj), cls)
if isinstance(cls, tuple):
for x in cls:
if isinstance(obj, x):
cls = x
break
standardMsg = f'{safe_repr(obj)} is an instance of {cls!r}'
self.fail(self._formatMessage(msg, standardMsg))
def assertIsSubclass(self, cls, superclass, msg=None):
try:
if issubclass(cls, superclass):
return
except TypeError:
if not isinstance(cls, type):
self.fail(self._formatMessage(msg, f'{cls!r} is not a class'))
raise
if isinstance(superclass, tuple):
standardMsg = f'{cls!r} is not a subclass of any of {superclass!r}'
else:
standardMsg = f'{cls!r} is not a subclass of {superclass!r}'
self.fail(self._formatMessage(msg, standardMsg))
def assertNotIsSubclass(self, cls, superclass, msg=None):
try:
if not issubclass(cls, superclass):
return
except TypeError:
if not isinstance(cls, type):
self.fail(self._formatMessage(msg, f'{cls!r} is not a class'))
raise
if isinstance(superclass, tuple):
for x in superclass:
if issubclass(cls, x):
superclass = x
break
standardMsg = f'{cls!r} is a subclass of {superclass!r}'
self.fail(self._formatMessage(msg, standardMsg))
def assertHasAttr(self, obj, name, msg=None):
if not hasattr(obj, name):
if isinstance(obj, types.ModuleType):
standardMsg = f'module {obj.__name__!r} has no attribute {name!r}'
elif isinstance(obj, type):
standardMsg = f'type object {obj.__name__!r} has no attribute {name!r}'
else:
standardMsg = f'{type(obj).__name__!r} object has no attribute {name!r}'
self.fail(self._formatMessage(msg, standardMsg))
def assertNotHasAttr(self, obj, name, msg=None):
if hasattr(obj, name):
if isinstance(obj, types.ModuleType):
standardMsg = f'module {obj.__name__!r} has unexpected attribute {name!r}'
elif isinstance(obj, type):
standardMsg = f'type object {obj.__name__!r} has unexpected attribute {name!r}'
else:
standardMsg = f'{type(obj).__name__!r} object has unexpected attribute {name!r}'
self.fail(self._formatMessage(msg, standardMsg))
def assertRaisesRegex(self, expected_exception, expected_regex,
@@ -1382,6 +1463,80 @@ class TestCase(object):
msg = self._formatMessage(msg, standardMsg)
raise self.failureException(msg)
def _tail_type_check(self, s, tails, msg):
if not isinstance(tails, tuple):
tails = (tails,)
for tail in tails:
if isinstance(tail, str):
if not isinstance(s, str):
self.fail(self._formatMessage(msg,
f'Expected str, not {type(s).__name__}'))
elif isinstance(tail, (bytes, bytearray)):
if not isinstance(s, (bytes, bytearray)):
self.fail(self._formatMessage(msg,
f'Expected bytes, not {type(s).__name__}'))
def assertStartsWith(self, s, prefix, msg=None):
try:
if s.startswith(prefix):
return
except (AttributeError, TypeError):
self._tail_type_check(s, prefix, msg)
raise
a = safe_repr(s, short=True)
b = safe_repr(prefix)
if isinstance(prefix, tuple):
standardMsg = f"{a} doesn't start with any of {b}"
else:
standardMsg = f"{a} doesn't start with {b}"
self.fail(self._formatMessage(msg, standardMsg))
def assertNotStartsWith(self, s, prefix, msg=None):
try:
if not s.startswith(prefix):
return
except (AttributeError, TypeError):
self._tail_type_check(s, prefix, msg)
raise
if isinstance(prefix, tuple):
for x in prefix:
if s.startswith(x):
prefix = x
break
a = safe_repr(s, short=True)
b = safe_repr(prefix)
self.fail(self._formatMessage(msg, f"{a} starts with {b}"))
def assertEndsWith(self, s, suffix, msg=None):
try:
if s.endswith(suffix):
return
except (AttributeError, TypeError):
self._tail_type_check(s, suffix, msg)
raise
a = safe_repr(s, short=True)
b = safe_repr(suffix)
if isinstance(suffix, tuple):
standardMsg = f"{a} doesn't end with any of {b}"
else:
standardMsg = f"{a} doesn't end with {b}"
self.fail(self._formatMessage(msg, standardMsg))
def assertNotEndsWith(self, s, suffix, msg=None):
try:
if not s.endswith(suffix):
return
except (AttributeError, TypeError):
self._tail_type_check(s, suffix, msg)
raise
if isinstance(suffix, tuple):
for x in suffix:
if s.endswith(x):
suffix = x
break
a = safe_repr(s, short=True)
b = safe_repr(suffix)
self.fail(self._formatMessage(msg, f"{a} ends with {b}"))
class FunctionTestCase(TestCase):
+46 -16
View File
@@ -1,12 +1,11 @@
"""Loading unittests."""
import functools
import os
import re
import sys
import traceback
import types
import functools
from fnmatch import fnmatch, fnmatchcase
from . import case, suite, util
@@ -274,6 +273,8 @@ class TestLoader(object):
self._top_level_dir = top_level_dir
is_not_importable = False
is_namespace = False
tests = []
if os.path.isdir(os.path.abspath(start_dir)):
start_dir = os.path.abspath(start_dir)
if start_dir != top_level_dir:
@@ -286,12 +287,25 @@ class TestLoader(object):
is_not_importable = True
else:
the_module = sys.modules[start_dir]
top_part = start_dir.split('.')[0]
try:
start_dir = os.path.abspath(
os.path.dirname((the_module.__file__)))
except AttributeError:
if the_module.__name__ in sys.builtin_module_names:
if not hasattr(the_module, "__file__") or the_module.__file__ is None:
# look for namespace packages
try:
spec = the_module.__spec__
except AttributeError:
spec = None
if spec and spec.submodule_search_locations is not None:
is_namespace = True
for path in the_module.__path__:
if (not set_implicit_top and
not path.startswith(top_level_dir)):
continue
self._top_level_dir = \
(path.split(the_module.__name__
.replace(".", os.path.sep))[0])
tests.extend(self._find_tests(path, pattern, namespace=True))
elif the_module.__name__ in sys.builtin_module_names:
# builtin module
raise TypeError('Can not use builtin modules '
'as dotted module names') from None
@@ -300,14 +314,27 @@ class TestLoader(object):
f"don't know how to discover from {the_module!r}"
) from None
else:
top_part = start_dir.split('.')[0]
start_dir = os.path.abspath(os.path.dirname((the_module.__file__)))
if set_implicit_top:
self._top_level_dir = self._get_directory_containing_module(top_part)
if not is_namespace:
if sys.modules[top_part].__file__ is None:
self._top_level_dir = os.path.dirname(the_module.__file__)
if self._top_level_dir not in sys.path:
sys.path.insert(0, self._top_level_dir)
else:
self._top_level_dir = \
self._get_directory_containing_module(top_part)
sys.path.remove(top_level_dir)
if is_not_importable:
raise ImportError('Start directory is not importable: %r' % start_dir)
tests = list(self._find_tests(start_dir, pattern))
if not is_namespace:
tests = list(self._find_tests(start_dir, pattern))
self._top_level_dir = original_top_level_dir
return self.suiteClass(tests)
@@ -343,7 +370,7 @@ class TestLoader(object):
# override this method to use alternative matching strategy
return fnmatch(path, pattern)
def _find_tests(self, start_dir, pattern):
def _find_tests(self, start_dir, pattern, namespace=False):
"""Used by discovery. Yields test suites it loads."""
# Handle the __init__ in this package
name = self._get_name_from_path(start_dir)
@@ -352,7 +379,8 @@ class TestLoader(object):
if name != '.' and name not in self._loading_packages:
# name is in self._loading_packages while we have called into
# loadTestsFromModule with name.
tests, should_recurse = self._find_test_path(start_dir, pattern)
tests, should_recurse = self._find_test_path(
start_dir, pattern, namespace)
if tests is not None:
yield tests
if not should_recurse:
@@ -363,7 +391,8 @@ class TestLoader(object):
paths = sorted(os.listdir(start_dir))
for path in paths:
full_path = os.path.join(start_dir, path)
tests, should_recurse = self._find_test_path(full_path, pattern)
tests, should_recurse = self._find_test_path(
full_path, pattern, False)
if tests is not None:
yield tests
if should_recurse:
@@ -371,11 +400,11 @@ class TestLoader(object):
name = self._get_name_from_path(full_path)
self._loading_packages.add(name)
try:
yield from self._find_tests(full_path, pattern)
yield from self._find_tests(full_path, pattern, False)
finally:
self._loading_packages.discard(name)
def _find_test_path(self, full_path, pattern):
def _find_test_path(self, full_path, pattern, namespace=False):
"""Used by discovery.
Loads tests from a single file, or a directories' __init__.py when
@@ -419,7 +448,8 @@ class TestLoader(object):
msg % (mod_name, module_dir, expected_dir))
return self.loadTestsFromModule(module, pattern=pattern), False
elif os.path.isdir(full_path):
if not os.path.isfile(os.path.join(full_path, '__init__.py')):
if (not namespace and
not os.path.isfile(os.path.join(full_path, '__init__.py'))):
return None, False
load_tests = None
+3 -3
View File
@@ -1,8 +1,8 @@
"""Unittest main program"""
import sys
import argparse
import os
import sys
from . import loader, runner
from .signals import installHandler
@@ -197,7 +197,7 @@ class TestProgram(object):
return parser
def _getMainArgParser(self, parent):
parser = argparse.ArgumentParser(parents=[parent])
parser = argparse.ArgumentParser(parents=[parent], color=True)
parser.prog = self.progName
parser.print_help = self._print_help
@@ -208,7 +208,7 @@ class TestProgram(object):
return parser
def _getDiscoveryArgParser(self, parent):
parser = argparse.ArgumentParser(parents=[parent])
parser = argparse.ArgumentParser(parents=[parent], color=True)
parser.prog = '%s discover' % self.progName
parser.epilog = ('For test discovery all test modules must be '
'importable from the top level directory of the '
+35 -17
View File
@@ -25,19 +25,20 @@ __all__ = (
import asyncio
import builtins
import contextlib
import io
import inspect
import io
import pkgutil
import pprint
import sys
import builtins
import pkgutil
from asyncio import iscoroutinefunction
import threading
from types import CodeType, ModuleType, MethodType
from unittest.util import safe_repr
from functools import wraps, partial
from dataclasses import fields, is_dataclass
from functools import partial, wraps
from inspect import iscoroutinefunction
from threading import RLock
from types import CodeType, MethodType, ModuleType
from unittest.util import safe_repr
class InvalidSpecError(Exception):
@@ -568,6 +569,11 @@ class NonCallableMock(Base):
__dict__['_mock_methods'] = spec
__dict__['_spec_asyncs'] = _spec_asyncs
def _mock_extend_spec_methods(self, spec_methods):
methods = self.__dict__.get('_mock_methods') or []
methods.extend(spec_methods)
self.__dict__['_mock_methods'] = methods
def __get_return_value(self):
ret = self._mock_return_value
if self._mock_delegate is not None:
@@ -1766,7 +1772,7 @@ def patch(
the patch is undone.
If `new` is omitted, then the target is replaced with an
`AsyncMock if the patched object is an async function or a
`AsyncMock` if the patched object is an async function or a
`MagicMock` otherwise. If `patch` is used as a decorator and `new` is
omitted, the created mock is passed in as an extra argument to the
decorated function. If `patch` is used as a context manager the created
@@ -1840,7 +1846,8 @@ def patch(
class _patch_dict(object):
"""
Patch a dictionary, or dictionary like object, and restore the dictionary
to its original state after the test.
to its original state after the test, where the restored dictionary is
a copy of the dictionary as it was before the test.
`in_dict` can be a dictionary or a mapping like container. If it is a
mapping then it must at least support getting, setting and deleting items
@@ -2176,8 +2183,6 @@ class MagicMixin(Base):
if getattr(self, "_mock_methods", None) is not None:
these_magics = orig_magics.intersection(self._mock_methods)
remove_magics = set()
remove_magics = orig_magics - these_magics
for entry in remove_magics:
@@ -2477,7 +2482,7 @@ class AsyncMock(AsyncMockMixin, AsyncMagicMixin, Mock):
recognized as an async function, and the result of a call is an awaitable:
>>> mock = AsyncMock()
>>> iscoroutinefunction(mock)
>>> inspect.iscoroutinefunction(mock)
True
>>> inspect.isawaitable(mock())
True
@@ -2767,6 +2772,16 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
f'[object={spec!r}]')
is_async_func = _is_async_func(spec)
_kwargs = {'spec': spec}
entries = [(entry, _missing) for entry in dir(spec)]
if is_type and instance and is_dataclass(spec):
is_dataclass_spec = True
dataclass_fields = fields(spec)
entries.extend((f.name, f.type) for f in dataclass_fields)
dataclass_spec_list = [f.name for f in dataclass_fields]
else:
is_dataclass_spec = False
if spec_set:
_kwargs = {'spec_set': spec}
elif spec is None:
@@ -2802,6 +2817,8 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
mock = Klass(parent=_parent, _new_parent=_parent, _new_name=_new_name,
name=_name, **_kwargs)
if is_dataclass_spec:
mock._mock_extend_spec_methods(dataclass_spec_list)
if isinstance(spec, FunctionTypes):
# should only happen at the top level because we don't
@@ -2823,7 +2840,7 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
_name='()', _parent=mock,
wraps=wrapped)
for entry in dir(spec):
for entry, original in entries:
if _is_magic(entry):
# MagicMock already does the useful magic methods for us
continue
@@ -2837,10 +2854,11 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
# AttributeError on being fetched?
# we could be resilient against it, or catch and propagate the
# exception when the attribute is fetched from the mock
try:
original = getattr(spec, entry)
except AttributeError:
continue
if original is _missing:
try:
original = getattr(spec, entry)
except AttributeError:
continue
child_kwargs = {'spec': original}
# Wrap child attributes also.
+5 -2
View File
@@ -3,9 +3,9 @@
import io
import sys
import traceback
from functools import wraps
from . import util
from functools import wraps
__unittest = True
@@ -189,7 +189,10 @@ class TestResult(object):
tb_e = traceback.TracebackException(
exctype, value, tb,
capture_locals=self.tb_locals, compact=True)
msgLines = list(tb_e.format())
from _colorize import can_colorize
colorize = hasattr(self, "stream") and can_colorize(file=self.stream)
msgLines = list(tb_e.format(colorize=colorize))
if self.buffer:
output = sys.stdout.getvalue()
+61 -40
View File
@@ -4,6 +4,8 @@ import sys
import time
import warnings
from _colorize import get_theme
from . import result
from .case import _SubTest
from .signals import registerResult
@@ -13,18 +15,18 @@ __unittest = True
class _WritelnDecorator(object):
"""Used to decorate file-like objects with a handy 'writeln' method"""
def __init__(self,stream):
def __init__(self, stream):
self.stream = stream
def __getattr__(self, attr):
if attr in ('stream', '__getstate__'):
raise AttributeError(attr)
return getattr(self.stream,attr)
return getattr(self.stream, attr)
def writeln(self, arg=None):
if arg:
self.write(arg)
self.write('\n') # text-mode streams translate to \r\n if needed
self.write('\n') # text-mode streams translate to \r\n if needed
class TextTestResult(result.TestResult):
@@ -43,6 +45,7 @@ class TextTestResult(result.TestResult):
self.showAll = verbosity > 1
self.dots = verbosity == 1
self.descriptions = descriptions
self._theme = get_theme(tty_file=stream).unittest
self._newline = True
self.durations = durations
@@ -76,86 +79,100 @@ class TextTestResult(result.TestResult):
def addSubTest(self, test, subtest, err):
if err is not None:
t = self._theme
if self.showAll:
if issubclass(err[0], subtest.failureException):
self._write_status(subtest, "FAIL")
self._write_status(subtest, f"{t.fail}FAIL{t.reset}")
else:
self._write_status(subtest, "ERROR")
self._write_status(subtest, f"{t.fail}ERROR{t.reset}")
elif self.dots:
if issubclass(err[0], subtest.failureException):
self.stream.write('F')
self.stream.write(f"{t.fail}F{t.reset}")
else:
self.stream.write('E')
self.stream.write(f"{t.fail}E{t.reset}")
self.stream.flush()
super(TextTestResult, self).addSubTest(test, subtest, err)
def addSuccess(self, test):
super(TextTestResult, self).addSuccess(test)
t = self._theme
if self.showAll:
self._write_status(test, "ok")
self._write_status(test, f"{t.passed}ok{t.reset}")
elif self.dots:
self.stream.write('.')
self.stream.write(f"{t.passed}.{t.reset}")
self.stream.flush()
def addError(self, test, err):
super(TextTestResult, self).addError(test, err)
t = self._theme
if self.showAll:
self._write_status(test, "ERROR")
self._write_status(test, f"{t.fail}ERROR{t.reset}")
elif self.dots:
self.stream.write('E')
self.stream.write(f"{t.fail}E{t.reset}")
self.stream.flush()
def addFailure(self, test, err):
super(TextTestResult, self).addFailure(test, err)
t = self._theme
if self.showAll:
self._write_status(test, "FAIL")
self._write_status(test, f"{t.fail}FAIL{t.reset}")
elif self.dots:
self.stream.write('F')
self.stream.write(f"{t.fail}F{t.reset}")
self.stream.flush()
def addSkip(self, test, reason):
super(TextTestResult, self).addSkip(test, reason)
t = self._theme
if self.showAll:
self._write_status(test, "skipped {0!r}".format(reason))
self._write_status(test, f"{t.warn}skipped{t.reset} {reason!r}")
elif self.dots:
self.stream.write("s")
self.stream.write(f"{t.warn}s{t.reset}")
self.stream.flush()
def addExpectedFailure(self, test, err):
super(TextTestResult, self).addExpectedFailure(test, err)
t = self._theme
if self.showAll:
self.stream.writeln("expected failure")
self.stream.writeln(f"{t.warn}expected failure{t.reset}")
self.stream.flush()
elif self.dots:
self.stream.write("x")
self.stream.write(f"{t.warn}x{t.reset}")
self.stream.flush()
def addUnexpectedSuccess(self, test):
super(TextTestResult, self).addUnexpectedSuccess(test)
t = self._theme
if self.showAll:
self.stream.writeln("unexpected success")
self.stream.writeln(f"{t.fail}unexpected success{t.reset}")
self.stream.flush()
elif self.dots:
self.stream.write("u")
self.stream.write(f"{t.fail}u{t.reset}")
self.stream.flush()
def printErrors(self):
t = self._theme
if self.dots or self.showAll:
self.stream.writeln()
self.stream.flush()
self.printErrorList('ERROR', self.errors)
self.printErrorList('FAIL', self.failures)
unexpectedSuccesses = getattr(self, 'unexpectedSuccesses', ())
self.printErrorList(f"{t.fail}ERROR{t.reset}", self.errors)
self.printErrorList(f"{t.fail}FAIL{t.reset}", self.failures)
unexpectedSuccesses = getattr(self, "unexpectedSuccesses", ())
if unexpectedSuccesses:
self.stream.writeln(self.separator1)
for test in unexpectedSuccesses:
self.stream.writeln(f"UNEXPECTED SUCCESS: {self.getDescription(test)}")
self.stream.writeln(
f"{t.fail}UNEXPECTED SUCCESS{t.fail_info}: "
f"{self.getDescription(test)}{t.reset}"
)
self.stream.flush()
def printErrorList(self, flavour, errors):
t = self._theme
for test, err in errors:
self.stream.writeln(self.separator1)
self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
self.stream.writeln(
f"{flavour}{t.fail_info}: {self.getDescription(test)}{t.reset}"
)
self.stream.writeln(self.separator2)
self.stream.writeln("%s" % err)
self.stream.flush()
@@ -232,7 +249,7 @@ class TextTestRunner(object):
if self.warnings:
# if self.warnings is set, use it to filter all the warnings
warnings.simplefilter(self.warnings)
startTime = time.perf_counter()
start_time = time.perf_counter()
startTestRun = getattr(result, 'startTestRun', None)
if startTestRun is not None:
startTestRun()
@@ -242,8 +259,8 @@ class TextTestRunner(object):
stopTestRun = getattr(result, 'stopTestRun', None)
if stopTestRun is not None:
stopTestRun()
stopTime = time.perf_counter()
timeTaken = stopTime - startTime
stop_time = time.perf_counter()
time_taken = stop_time - start_time
result.printErrors()
if self.durations is not None:
self._printDurations(result)
@@ -253,10 +270,10 @@ class TextTestRunner(object):
run = result.testsRun
self.stream.writeln("Ran %d test%s in %.3fs" %
(run, run != 1 and "s" or "", timeTaken))
(run, run != 1 and "s" or "", time_taken))
self.stream.writeln()
expectedFails = unexpectedSuccesses = skipped = 0
expected_fails = unexpected_successes = skipped = 0
try:
results = map(len, (result.expectedFailures,
result.unexpectedSuccesses,
@@ -264,26 +281,30 @@ class TextTestRunner(object):
except AttributeError:
pass
else:
expectedFails, unexpectedSuccesses, skipped = results
expected_fails, unexpected_successes, skipped = results
infos = []
t = get_theme(tty_file=self.stream).unittest
if not result.wasSuccessful():
self.stream.write("FAILED")
self.stream.write(f"{t.fail_info}FAILED{t.reset}")
failed, errored = len(result.failures), len(result.errors)
if failed:
infos.append("failures=%d" % failed)
infos.append(f"{t.fail_info}failures={failed}{t.reset}")
if errored:
infos.append("errors=%d" % errored)
infos.append(f"{t.fail_info}errors={errored}{t.reset}")
elif run == 0 and not skipped:
self.stream.write("NO TESTS RAN")
self.stream.write(f"{t.warn}NO TESTS RAN{t.reset}")
else:
self.stream.write("OK")
self.stream.write(f"{t.passed}OK{t.reset}")
if skipped:
infos.append("skipped=%d" % skipped)
if expectedFails:
infos.append("expected failures=%d" % expectedFails)
if unexpectedSuccesses:
infos.append("unexpected successes=%d" % unexpectedSuccesses)
infos.append(f"{t.warn}skipped={skipped}{t.reset}")
if expected_fails:
infos.append(f"{t.warn}expected failures={expected_fails}{t.reset}")
if unexpected_successes:
infos.append(
f"{t.fail}unexpected successes={unexpected_successes}{t.reset}"
)
if infos:
self.stream.writeln(" (%s)" % (", ".join(infos),))
else:
-1
View File
@@ -1,6 +1,5 @@
import signal
import weakref
from functools import wraps
__unittest = True
+1 -2
View File
@@ -2,8 +2,7 @@
import sys
from . import case
from . import util
from . import case, util
__unittest = True
+1 -1
View File
@@ -1,6 +1,6 @@
"""Various utility functions."""
from collections import namedtuple, Counter
from collections import Counter, namedtuple
from os.path import commonprefix
__unittest = True