Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d15642e

Browse files
committed
Issue #17778: Fix test discovery for test_multiprocessing. (Patch by
Zachary Ware.)
1 parent 265fba4 commit d15642e

2 files changed

Lines changed: 107 additions & 122 deletions

File tree

Lib/test/test_multiprocessing.py

Lines changed: 104 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import random
2020
import logging
2121
import struct
22+
import operator
2223
import test.support
2324
import test.script_helper
2425

@@ -1624,6 +1625,18 @@ def mul(x, y):
16241625

16251626
class _TestPool(BaseTestCase):
16261627

1628+
@classmethod
1629+
def setUpClass(cls):
1630+
super().setUpClass()
1631+
cls.pool = cls.Pool(4)
1632+
1633+
@classmethod
1634+
def tearDownClass(cls):
1635+
cls.pool.terminate()
1636+
cls.pool.join()
1637+
cls.pool = None
1638+
super().tearDownClass()
1639+
16271640
def test_apply(self):
16281641
papply = self.pool.apply
16291642
self.assertEqual(papply(sqr, (5,)), sqr(5))
@@ -1715,15 +1728,6 @@ def test_make_pool(self):
17151728
p.join()
17161729

17171730
def test_terminate(self):
1718-
if self.TYPE == 'manager':
1719-
# On Unix a forked process increfs each shared object to
1720-
# which its parent process held a reference. If the
1721-
# forked process gets terminated then there is likely to
1722-
# be a reference leak. So to prevent
1723-
# _TestZZZNumberOfObjects from failing we skip this test
1724-
# when using a manager.
1725-
return
1726-
17271731
result = self.pool.map_async(
17281732
time.sleep, [0.1 for i in range(10000)], chunksize=1
17291733
)
@@ -1751,7 +1755,6 @@ def test_context(self):
17511755
with multiprocessing.Pool(2) as p:
17521756
r = p.map_async(sqr, L)
17531757
self.assertEqual(r.get(), expected)
1754-
print(p._state)
17551758
self.assertRaises(ValueError, p.map_async, sqr, L)
17561759

17571760
def raising():
@@ -1845,35 +1848,6 @@ def test_pool_worker_lifetime_early_close(self):
18451848
for (j, res) in enumerate(results):
18461849
self.assertEqual(res.get(), sqr(j))
18471850

1848-
1849-
#
1850-
# Test that manager has expected number of shared objects left
1851-
#
1852-
1853-
class _TestZZZNumberOfObjects(BaseTestCase):
1854-
# Because test cases are sorted alphabetically, this one will get
1855-
# run after all the other tests for the manager. It tests that
1856-
# there have been no "reference leaks" for the manager's shared
1857-
# objects. Note the comment in _TestPool.test_terminate().
1858-
1859-
# If some other test using ManagerMixin.manager fails, then the
1860-
# raised exception may keep alive a frame which holds a reference
1861-
# to a managed object. This will cause test_number_of_objects to
1862-
# also fail.
1863-
ALLOWED_TYPES = ('manager',)
1864-
1865-
def test_number_of_objects(self):
1866-
EXPECTED_NUMBER = 1 # the pool object is still alive
1867-
multiprocessing.active_children() # discard dead process objs
1868-
gc.collect() # do garbage collection
1869-
refs = self.manager._number_of_objects()
1870-
debug_info = self.manager._debug_info()
1871-
if refs != EXPECTED_NUMBER:
1872-
print(self.manager._debug_info())
1873-
print(debug_info)
1874-
1875-
self.assertEqual(refs, EXPECTED_NUMBER)
1876-
18771851
#
18781852
# Test of creating a customized manager class
18791853
#
@@ -2051,7 +2025,7 @@ def test_rapid_restart(self):
20512025
address=addr, authkey=authkey, serializer=SERIALIZER)
20522026
try:
20532027
manager.start()
2054-
except IOError as e:
2028+
except OSError as e:
20552029
if e.errno != errno.EADDRINUSE:
20562030
raise
20572031
# Retry after some time, in case the old socket was lingering
@@ -2165,9 +2139,9 @@ def test_duplex_false(self):
21652139
self.assertEqual(reader.writable, False)
21662140
self.assertEqual(writer.readable, False)
21672141
self.assertEqual(writer.writable, True)
2168-
self.assertRaises(IOError, reader.send, 2)
2169-
self.assertRaises(IOError, writer.recv)
2170-
self.assertRaises(IOError, writer.poll)
2142+
self.assertRaises(OSError, reader.send, 2)
2143+
self.assertRaises(OSError, writer.recv)
2144+
self.assertRaises(OSError, writer.poll)
21712145

21722146
def test_spawn_close(self):
21732147
# We test that a pipe connection can be closed by parent
@@ -2329,8 +2303,8 @@ def test_context(self):
23292303
if self.TYPE == 'processes':
23302304
self.assertTrue(a.closed)
23312305
self.assertTrue(b.closed)
2332-
self.assertRaises(IOError, a.recv)
2333-
self.assertRaises(IOError, b.recv)
2306+
self.assertRaises(OSError, a.recv)
2307+
self.assertRaises(OSError, b.recv)
23342308

23352309
class _TestListener(BaseTestCase):
23362310

@@ -2351,7 +2325,7 @@ def test_context(self):
23512325
self.assertEqual(d.recv(), 1729)
23522326

23532327
if self.TYPE == 'processes':
2354-
self.assertRaises(IOError, l.accept)
2328+
self.assertRaises(OSError, l.accept)
23552329

23562330
class _TestListenerClient(BaseTestCase):
23572331

@@ -2401,7 +2375,7 @@ def test_issue16955(self):
24012375
c.close()
24022376
l.close()
24032377

2404-
class _TestPoll(unittest.TestCase):
2378+
class _TestPoll(BaseTestCase):
24052379

24062380
ALLOWED_TYPES = ('processes', 'threads')
24072381

@@ -2942,27 +2916,18 @@ class TestInvalidHandle(unittest.TestCase):
29422916
def test_invalid_handles(self):
29432917
conn = multiprocessing.connection.Connection(44977608)
29442918
try:
2945-
self.assertRaises((ValueError, IOError), conn.poll)
2919+
self.assertRaises((ValueError, OSError), conn.poll)
29462920
finally:
29472921
# Hack private attribute _handle to avoid printing an error
29482922
# in conn.__del__
29492923
conn._handle = None
2950-
self.assertRaises((ValueError, IOError),
2924+
self.assertRaises((ValueError, OSError),
29512925
multiprocessing.connection.Connection, -1)
29522926

29532927
#
29542928
# Functions used to create test cases from the base ones in this module
29552929
#
29562930

2957-
def get_attributes(Source, names):
2958-
d = {}
2959-
for name in names:
2960-
obj = getattr(Source, name)
2961-
if type(obj) == type(get_attributes):
2962-
obj = staticmethod(obj)
2963-
d[name] = obj
2964-
return d
2965-
29662931
def create_test_cases(Mixin, type):
29672932
result = {}
29682933
glob = globals()
@@ -2975,10 +2940,10 @@ def create_test_cases(Mixin, type):
29752940
assert set(base.ALLOWED_TYPES) <= ALL_TYPES, set(base.ALLOWED_TYPES)
29762941
if type in base.ALLOWED_TYPES:
29772942
newname = 'With' + Type + name[1:]
2978-
class Temp(base, unittest.TestCase, Mixin):
2943+
class Temp(base, Mixin, unittest.TestCase):
29792944
pass
29802945
result[newname] = Temp
2981-
Temp.__name__ = newname
2946+
Temp.__name__ = Temp.__qualname__ = newname
29822947
Temp.__module__ = Mixin.__module__
29832948
return result
29842949

@@ -2989,12 +2954,24 @@ class Temp(base, unittest.TestCase, Mixin):
29892954
class ProcessesMixin(object):
29902955
TYPE = 'processes'
29912956
Process = multiprocessing.Process
2992-
locals().update(get_attributes(multiprocessing, (
2993-
'Queue', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore',
2994-
'Condition', 'Event', 'Barrier', 'Value', 'Array', 'RawValue',
2995-
'RawArray', 'current_process', 'active_children', 'Pipe',
2996-
'connection', 'JoinableQueue', 'Pool'
2997-
)))
2957+
connection = multiprocessing.connection
2958+
current_process = staticmethod(multiprocessing.current_process)
2959+
active_children = staticmethod(multiprocessing.active_children)
2960+
Pool = staticmethod(multiprocessing.Pool)
2961+
Pipe = staticmethod(multiprocessing.Pipe)
2962+
Queue = staticmethod(multiprocessing.Queue)
2963+
JoinableQueue = staticmethod(multiprocessing.JoinableQueue)
2964+
Lock = staticmethod(multiprocessing.Lock)
2965+
RLock = staticmethod(multiprocessing.RLock)
2966+
Semaphore = staticmethod(multiprocessing.Semaphore)
2967+
BoundedSemaphore = staticmethod(multiprocessing.BoundedSemaphore)
2968+
Condition = staticmethod(multiprocessing.Condition)
2969+
Event = staticmethod(multiprocessing.Event)
2970+
Barrier = staticmethod(multiprocessing.Barrier)
2971+
Value = staticmethod(multiprocessing.Value)
2972+
Array = staticmethod(multiprocessing.Array)
2973+
RawValue = staticmethod(multiprocessing.RawValue)
2974+
RawArray = staticmethod(multiprocessing.RawArray)
29982975

29992976
testcases_processes = create_test_cases(ProcessesMixin, type='processes')
30002977
globals().update(testcases_processes)
@@ -3003,12 +2980,48 @@ class ProcessesMixin(object):
30032980
class ManagerMixin(object):
30042981
TYPE = 'manager'
30052982
Process = multiprocessing.Process
3006-
manager = object.__new__(multiprocessing.managers.SyncManager)
3007-
locals().update(get_attributes(manager, (
3008-
'Queue', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore',
3009-
'Condition', 'Event', 'Barrier', 'Value', 'Array', 'list', 'dict',
3010-
'Namespace', 'JoinableQueue', 'Pool'
3011-
)))
2983+
Queue = property(operator.attrgetter('manager.Queue'))
2984+
JoinableQueue = property(operator.attrgetter('manager.JoinableQueue'))
2985+
Lock = property(operator.attrgetter('manager.Lock'))
2986+
RLock = property(operator.attrgetter('manager.RLock'))
2987+
Semaphore = property(operator.attrgetter('manager.Semaphore'))
2988+
BoundedSemaphore = property(operator.attrgetter('manager.BoundedSemaphore'))
2989+
Condition = property(operator.attrgetter('manager.Condition'))
2990+
Event = property(operator.attrgetter('manager.Event'))
2991+
Barrier = property(operator.attrgetter('manager.Barrier'))
2992+
Value = property(operator.attrgetter('manager.Value'))
2993+
Array = property(operator.attrgetter('manager.Array'))
2994+
list = property(operator.attrgetter('manager.list'))
2995+
dict = property(operator.attrgetter('manager.dict'))
2996+
Namespace = property(operator.attrgetter('manager.Namespace'))
2997+
2998+
@classmethod
2999+
def Pool(cls, *args, **kwds):
3000+
return cls.manager.Pool(*args, **kwds)
3001+
3002+
@classmethod
3003+
def setUpClass(cls):
3004+
cls.manager = multiprocessing.Manager()
3005+
3006+
@classmethod
3007+
def tearDownClass(cls):
3008+
# only the manager process should be returned by active_children()
3009+
# but this can take a bit on slow machines, so wait a few seconds
3010+
# if there are other children too (see #17395)
3011+
t = 0.01
3012+
while len(multiprocessing.active_children()) > 1 and t < 5:
3013+
time.sleep(t)
3014+
t *= 2
3015+
gc.collect() # do garbage collection
3016+
if cls.manager._number_of_objects() != 0:
3017+
# This is not really an error since some tests do not
3018+
# ensure that all processes which hold a reference to a
3019+
# managed object have been joined.
3020+
print('Shared objects which still exist at manager shutdown:')
3021+
print(cls.manager._debug_info())
3022+
cls.manager.shutdown()
3023+
cls.manager.join()
3024+
cls.manager = None
30123025

30133026
testcases_manager = create_test_cases(ManagerMixin, type='manager')
30143027
globals().update(testcases_manager)
@@ -3017,16 +3030,27 @@ class ManagerMixin(object):
30173030
class ThreadsMixin(object):
30183031
TYPE = 'threads'
30193032
Process = multiprocessing.dummy.Process
3020-
locals().update(get_attributes(multiprocessing.dummy, (
3021-
'Queue', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore',
3022-
'Condition', 'Event', 'Barrier', 'Value', 'Array', 'current_process',
3023-
'active_children', 'Pipe', 'connection', 'dict', 'list',
3024-
'Namespace', 'JoinableQueue', 'Pool'
3025-
)))
3033+
connection = multiprocessing.dummy.connection
3034+
current_process = staticmethod(multiprocessing.dummy.current_process)
3035+
active_children = staticmethod(multiprocessing.dummy.active_children)
3036+
Pool = staticmethod(multiprocessing.Pool)
3037+
Pipe = staticmethod(multiprocessing.dummy.Pipe)
3038+
Queue = staticmethod(multiprocessing.dummy.Queue)
3039+
JoinableQueue = staticmethod(multiprocessing.dummy.JoinableQueue)
3040+
Lock = staticmethod(multiprocessing.dummy.Lock)
3041+
RLock = staticmethod(multiprocessing.dummy.RLock)
3042+
Semaphore = staticmethod(multiprocessing.dummy.Semaphore)
3043+
BoundedSemaphore = staticmethod(multiprocessing.dummy.BoundedSemaphore)
3044+
Condition = staticmethod(multiprocessing.dummy.Condition)
3045+
Event = staticmethod(multiprocessing.dummy.Event)
3046+
Barrier = staticmethod(multiprocessing.dummy.Barrier)
3047+
Value = staticmethod(multiprocessing.dummy.Value)
3048+
Array = staticmethod(multiprocessing.dummy.Array)
30263049

30273050
testcases_threads = create_test_cases(ThreadsMixin, type='threads')
30283051
globals().update(testcases_threads)
30293052

3053+
30303054
class OtherTest(unittest.TestCase):
30313055
# TODO: add more tests for deliver/answer challenge.
30323056
def test_deliver_challenge_auth_failure(self):
@@ -3532,16 +3556,7 @@ def test_ignore_listener(self):
35323556
#
35333557
#
35343558

3535-
testcases_other = [OtherTest, TestInvalidHandle, TestInitializers,
3536-
TestStdinBadfiledescriptor, TestWait, TestInvalidFamily,
3537-
TestFlags, TestTimeouts, TestNoForkBomb,
3538-
TestForkAwareThreadLock, TestIgnoreEINTR]
3539-
3540-
#
3541-
#
3542-
#
3543-
3544-
def test_main(run=None):
3559+
def setUpModule():
35453560
if sys.platform.startswith("linux"):
35463561
try:
35473562
lock = multiprocessing.RLock()
@@ -3550,43 +3565,10 @@ def test_main(run=None):
35503565

35513566
check_enough_semaphores()
35523567

3553-
if run is None:
3554-
from test.support import run_unittest as run
3555-
35563568
util.get_temp_dir() # creates temp directory for use by all processes
35573569

35583570
multiprocessing.get_logger().setLevel(LOG_LEVEL)
35593571

3560-
ProcessesMixin.pool = multiprocessing.Pool(4)
3561-
ThreadsMixin.pool = multiprocessing.dummy.Pool(4)
3562-
ManagerMixin.manager.__init__()
3563-
ManagerMixin.manager.start()
3564-
ManagerMixin.pool = ManagerMixin.manager.Pool(4)
3565-
3566-
testcases = (
3567-
sorted(testcases_processes.values(), key=lambda tc:tc.__name__) +
3568-
sorted(testcases_threads.values(), key=lambda tc:tc.__name__) +
3569-
sorted(testcases_manager.values(), key=lambda tc:tc.__name__) +
3570-
testcases_other
3571-
)
3572-
3573-
loadTestsFromTestCase = unittest.defaultTestLoader.loadTestsFromTestCase
3574-
suite = unittest.TestSuite(loadTestsFromTestCase(tc) for tc in testcases)
3575-
try:
3576-
run(suite)
3577-
finally:
3578-
ThreadsMixin.pool.terminate()
3579-
ProcessesMixin.pool.terminate()
3580-
ManagerMixin.pool.terminate()
3581-
ManagerMixin.pool.join()
3582-
ManagerMixin.manager.shutdown()
3583-
ManagerMixin.manager.join()
3584-
ThreadsMixin.pool.join()
3585-
ProcessesMixin.pool.join()
3586-
del ProcessesMixin.pool, ThreadsMixin.pool, ManagerMixin.pool
3587-
3588-
def main():
3589-
test_main(unittest.TextTestRunner(verbosity=2).run)
35903572

35913573
if __name__ == '__main__':
3592-
main()
3574+
unittest.main()

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ Core and Builtins
4949
Library
5050
-------
5151

52+
- Issue #17778: Fix test discovery for test_multiprocessing. (Patch by
53+
Zachary Ware.)
54+
5255
- Issue #18431: The new email header parser now decodes RFC2047 encoded words
5356
in structured headers.
5457

0 commit comments

Comments
 (0)