Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 98c16c9

Browse filesBrowse files
authored
bpo-41833: threading.Thread now uses the target name (GH-22357)
1 parent 2e4dd33 commit 98c16c9
Copy full SHA for 98c16c9

File tree

4 files changed

+55
-10
lines changed
Filter options

4 files changed

+55
-10
lines changed

‎Doc/library/threading.rst

Copy file name to clipboardExpand all lines: Doc/library/threading.rst
+7-2Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,10 @@ since it is impossible to detect the termination of alien threads.
264264
*target* is the callable object to be invoked by the :meth:`run` method.
265265
Defaults to ``None``, meaning nothing is called.
266266

267-
*name* is the thread name. By default, a unique name is constructed of the
268-
form "Thread-*N*" where *N* is a small decimal number.
267+
*name* is the thread name. By default, a unique name is constructed
268+
of the form "Thread-*N*" where *N* is a small decimal number,
269+
or "Thread-*N* (target)" where "target" is ``target.__name__`` if the
270+
*target* argument is specified.
269271

270272
*args* is the argument tuple for the target invocation. Defaults to ``()``.
271273

@@ -280,6 +282,9 @@ since it is impossible to detect the termination of alien threads.
280282
base class constructor (``Thread.__init__()``) before doing anything else to
281283
the thread.
282284

285+
.. versionchanged:: 3.10
286+
Use the *target* name if *name* argument is omitted.
287+
283288
.. versionchanged:: 3.3
284289
Added the *daemon* argument.
285290

‎Lib/test/test_threading.py

Copy file name to clipboardExpand all lines: Lib/test/test_threading.py
+31-3Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import signal
2121
import textwrap
2222

23+
from unittest import mock
2324
from test import lock_tests
2425
from test import support
2526

@@ -86,6 +87,33 @@ def tearDown(self):
8687

8788
class ThreadTests(BaseTestCase):
8889

90+
@cpython_only
91+
def test_name(self):
92+
def func(): pass
93+
94+
thread = threading.Thread(name="myname1")
95+
self.assertEqual(thread.name, "myname1")
96+
97+
# Convert int name to str
98+
thread = threading.Thread(name=123)
99+
self.assertEqual(thread.name, "123")
100+
101+
# target name is ignored if name is specified
102+
thread = threading.Thread(target=func, name="myname2")
103+
self.assertEqual(thread.name, "myname2")
104+
105+
with mock.patch.object(threading, '_counter', return_value=2):
106+
thread = threading.Thread(name="")
107+
self.assertEqual(thread.name, "Thread-2")
108+
109+
with mock.patch.object(threading, '_counter', return_value=3):
110+
thread = threading.Thread()
111+
self.assertEqual(thread.name, "Thread-3")
112+
113+
with mock.patch.object(threading, '_counter', return_value=5):
114+
thread = threading.Thread(target=func)
115+
self.assertEqual(thread.name, "Thread-5 (func)")
116+
89117
# Create a bunch of threads, let each do some work, wait until all are
90118
# done.
91119
def test_various_ops(self):
@@ -531,7 +559,7 @@ def test_main_thread_after_fork_from_nonmain_thread(self):
531559
import os, threading, sys
532560
from test import support
533561
534-
def f():
562+
def func():
535563
pid = os.fork()
536564
if pid == 0:
537565
main = threading.main_thread()
@@ -544,14 +572,14 @@ def f():
544572
else:
545573
support.wait_process(pid, exitcode=0)
546574
547-
th = threading.Thread(target=f)
575+
th = threading.Thread(target=func)
548576
th.start()
549577
th.join()
550578
"""
551579
_, out, err = assert_python_ok("-c", code)
552580
data = out.decode().replace('\r', '')
553581
self.assertEqual(err, b"")
554-
self.assertEqual(data, "Thread-1\nTrue\nTrue\n")
582+
self.assertEqual(data, "Thread-1 (func)\nTrue\nTrue\n")
555583

556584
def test_main_thread_during_shutdown(self):
557585
# bpo-31516: current_thread() should still point to the main thread

‎Lib/threading.py

Copy file name to clipboardExpand all lines: Lib/threading.py
+15-5Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -745,10 +745,9 @@ class BrokenBarrierError(RuntimeError):
745745

746746

747747
# Helper to generate new thread names
748-
_counter = _count().__next__
749-
_counter() # Consume 0 so first non-main thread has id 1.
750-
def _newname(template="Thread-%d"):
751-
return template % _counter()
748+
_counter = _count(1).__next__
749+
def _newname(name_template):
750+
return name_template % _counter()
752751

753752
# Active thread administration
754753
_active_limbo_lock = _allocate_lock()
@@ -800,8 +799,19 @@ class is implemented.
800799
assert group is None, "group argument must be None for now"
801800
if kwargs is None:
802801
kwargs = {}
802+
if name:
803+
name = str(name)
804+
else:
805+
name = _newname("Thread-%d")
806+
if target is not None:
807+
try:
808+
target_name = target.__name__
809+
name += f" ({target_name})"
810+
except AttributeError:
811+
pass
812+
803813
self._target = target
804-
self._name = str(name or _newname())
814+
self._name = name
805815
self._args = args
806816
self._kwargs = kwargs
807817
if daemon is not None:
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The :class:`threading.Thread` constructor now uses the target name if the
2+
*target* argument is specified but the *name* argument is omitted.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.