bpo-41833: threading.Thread now uses the target name (GH-22357)
This commit is contained in:
parent
2e4dd336e5
commit
98c16c991d
|
@ -264,8 +264,10 @@ since it is impossible to detect the termination of alien threads.
|
||||||
*target* is the callable object to be invoked by the :meth:`run` method.
|
*target* is the callable object to be invoked by the :meth:`run` method.
|
||||||
Defaults to ``None``, meaning nothing is called.
|
Defaults to ``None``, meaning nothing is called.
|
||||||
|
|
||||||
*name* is the thread name. By default, a unique name is constructed of the
|
*name* is the thread name. By default, a unique name is constructed
|
||||||
form "Thread-*N*" where *N* is a small decimal number.
|
of the form "Thread-*N*" where *N* is a small decimal number,
|
||||||
|
or "Thread-*N* (target)" where "target" is ``target.__name__`` if the
|
||||||
|
*target* argument is specified.
|
||||||
|
|
||||||
*args* is the argument tuple for the target invocation. Defaults to ``()``.
|
*args* is the argument tuple for the target invocation. Defaults to ``()``.
|
||||||
|
|
||||||
|
@ -280,6 +282,9 @@ since it is impossible to detect the termination of alien threads.
|
||||||
base class constructor (``Thread.__init__()``) before doing anything else to
|
base class constructor (``Thread.__init__()``) before doing anything else to
|
||||||
the thread.
|
the thread.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.10
|
||||||
|
Use the *target* name if *name* argument is omitted.
|
||||||
|
|
||||||
.. versionchanged:: 3.3
|
.. versionchanged:: 3.3
|
||||||
Added the *daemon* argument.
|
Added the *daemon* argument.
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import subprocess
|
||||||
import signal
|
import signal
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
|
from unittest import mock
|
||||||
from test import lock_tests
|
from test import lock_tests
|
||||||
from test import support
|
from test import support
|
||||||
|
|
||||||
|
@ -86,6 +87,33 @@ class BaseTestCase(unittest.TestCase):
|
||||||
|
|
||||||
class ThreadTests(BaseTestCase):
|
class ThreadTests(BaseTestCase):
|
||||||
|
|
||||||
|
@cpython_only
|
||||||
|
def test_name(self):
|
||||||
|
def func(): pass
|
||||||
|
|
||||||
|
thread = threading.Thread(name="myname1")
|
||||||
|
self.assertEqual(thread.name, "myname1")
|
||||||
|
|
||||||
|
# Convert int name to str
|
||||||
|
thread = threading.Thread(name=123)
|
||||||
|
self.assertEqual(thread.name, "123")
|
||||||
|
|
||||||
|
# target name is ignored if name is specified
|
||||||
|
thread = threading.Thread(target=func, name="myname2")
|
||||||
|
self.assertEqual(thread.name, "myname2")
|
||||||
|
|
||||||
|
with mock.patch.object(threading, '_counter', return_value=2):
|
||||||
|
thread = threading.Thread(name="")
|
||||||
|
self.assertEqual(thread.name, "Thread-2")
|
||||||
|
|
||||||
|
with mock.patch.object(threading, '_counter', return_value=3):
|
||||||
|
thread = threading.Thread()
|
||||||
|
self.assertEqual(thread.name, "Thread-3")
|
||||||
|
|
||||||
|
with mock.patch.object(threading, '_counter', return_value=5):
|
||||||
|
thread = threading.Thread(target=func)
|
||||||
|
self.assertEqual(thread.name, "Thread-5 (func)")
|
||||||
|
|
||||||
# Create a bunch of threads, let each do some work, wait until all are
|
# Create a bunch of threads, let each do some work, wait until all are
|
||||||
# done.
|
# done.
|
||||||
def test_various_ops(self):
|
def test_various_ops(self):
|
||||||
|
@ -531,7 +559,7 @@ class ThreadTests(BaseTestCase):
|
||||||
import os, threading, sys
|
import os, threading, sys
|
||||||
from test import support
|
from test import support
|
||||||
|
|
||||||
def f():
|
def func():
|
||||||
pid = os.fork()
|
pid = os.fork()
|
||||||
if pid == 0:
|
if pid == 0:
|
||||||
main = threading.main_thread()
|
main = threading.main_thread()
|
||||||
|
@ -544,14 +572,14 @@ class ThreadTests(BaseTestCase):
|
||||||
else:
|
else:
|
||||||
support.wait_process(pid, exitcode=0)
|
support.wait_process(pid, exitcode=0)
|
||||||
|
|
||||||
th = threading.Thread(target=f)
|
th = threading.Thread(target=func)
|
||||||
th.start()
|
th.start()
|
||||||
th.join()
|
th.join()
|
||||||
"""
|
"""
|
||||||
_, out, err = assert_python_ok("-c", code)
|
_, out, err = assert_python_ok("-c", code)
|
||||||
data = out.decode().replace('\r', '')
|
data = out.decode().replace('\r', '')
|
||||||
self.assertEqual(err, b"")
|
self.assertEqual(err, b"")
|
||||||
self.assertEqual(data, "Thread-1\nTrue\nTrue\n")
|
self.assertEqual(data, "Thread-1 (func)\nTrue\nTrue\n")
|
||||||
|
|
||||||
def test_main_thread_during_shutdown(self):
|
def test_main_thread_during_shutdown(self):
|
||||||
# bpo-31516: current_thread() should still point to the main thread
|
# bpo-31516: current_thread() should still point to the main thread
|
||||||
|
|
|
@ -745,10 +745,9 @@ class BrokenBarrierError(RuntimeError):
|
||||||
|
|
||||||
|
|
||||||
# Helper to generate new thread names
|
# Helper to generate new thread names
|
||||||
_counter = _count().__next__
|
_counter = _count(1).__next__
|
||||||
_counter() # Consume 0 so first non-main thread has id 1.
|
def _newname(name_template):
|
||||||
def _newname(template="Thread-%d"):
|
return name_template % _counter()
|
||||||
return template % _counter()
|
|
||||||
|
|
||||||
# Active thread administration
|
# Active thread administration
|
||||||
_active_limbo_lock = _allocate_lock()
|
_active_limbo_lock = _allocate_lock()
|
||||||
|
@ -800,8 +799,19 @@ class Thread:
|
||||||
assert group is None, "group argument must be None for now"
|
assert group is None, "group argument must be None for now"
|
||||||
if kwargs is None:
|
if kwargs is None:
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
|
if name:
|
||||||
|
name = str(name)
|
||||||
|
else:
|
||||||
|
name = _newname("Thread-%d")
|
||||||
|
if target is not None:
|
||||||
|
try:
|
||||||
|
target_name = target.__name__
|
||||||
|
name += f" ({target_name})"
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
self._target = target
|
self._target = target
|
||||||
self._name = str(name or _newname())
|
self._name = name
|
||||||
self._args = args
|
self._args = args
|
||||||
self._kwargs = kwargs
|
self._kwargs = kwargs
|
||||||
if daemon is not None:
|
if daemon is not None:
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
The :class:`threading.Thread` constructor now uses the target name if the
|
||||||
|
*target* argument is specified but the *name* argument is omitted.
|
Loading…
Reference in New Issue