Skip to content

Commit 1603648

Browse files
authored
Include the module name in create_task task names in more situations (#1234)
1 parent bf45a82 commit 1603648

5 files changed

Lines changed: 44 additions & 19 deletions

File tree

docs/versionhistory.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,15 @@ Version history
33

44
This library adheres to `Semantic Versioning 2.0 <http://semver.org/>`_.
55

6+
**UNRELEASED**
7+
8+
- Changed the default name for a task spawned with ``TaskGroup.create_task(func())`` to
9+
match the default task name for the analogous task spawned with
10+
``TaskGroup.start_soon(func)`` or ``TaskGroup.start(func)`` in more situations.
11+
Previously, the default name of a ``TaskGroup.create_task`` task never included the
12+
module name. (The default name for a task spawned with ``TaskGroup.start_soon`` or
13+
``TaskGroup.start`` typically includes the module name.) (PR by @gschaffner)
14+
615
**4.14.2**
716

817
- Changed ``ByteReceiveStream.receive()`` implementations to raise a ``ValueError`` when

src/anyio/_backends/_asyncio.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@
101101
UNIXDatagramPacketType,
102102
)
103103
from ..abc._eventloop import StrOrBytesPath
104-
from ..abc._tasks import call_for_coroutine, get_callable_name
104+
from ..abc._tasks import call_for_coroutine, get_callable_name, get_coro_name
105105
from ..lowlevel import RunVar
106106
from ..streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
107107

@@ -926,10 +926,12 @@ def create_task(
926926
"This task group is not active; no new tasks can be started."
927927
)
928928

929+
final_name = get_coro_name(coro, name)
930+
929931
if context is not None:
930-
return context.run(self._spawn, coro, name=name)
932+
return context.run(self._spawn, coro, name=final_name)
931933
else:
932-
return self._spawn(coro, name=name)
934+
return self._spawn(coro, name=final_name)
933935

934936
async def start(
935937
self,

src/anyio/_backends/_trio.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484
from .._core._tasks import TaskHandle
8585
from ..abc import IPSockAddrType, UDPPacketType, UNIXDatagramPacketType
8686
from ..abc._eventloop import AsyncBackend, StrOrBytesPath
87-
from ..abc._tasks import T_contra, call_for_coroutine, get_callable_name
87+
from ..abc._tasks import T_contra, call_for_coroutine, get_callable_name, get_coro_name
8888
from ..streams.memory import MemoryObjectSendStream
8989

9090
if TYPE_CHECKING:
@@ -267,7 +267,8 @@ def create_task(
267267
raise TypeError(f"expected a coroutine, got {coro.__class__.__qualname__}")
268268

269269
self._check_active(coro)
270-
handle = TaskHandle(coro, name)
270+
final_name = get_coro_name(coro, name)
271+
handle = TaskHandle(coro, final_name)
271272
if context is not None:
272273
context.run(
273274
partial(self._nursery.start_soon, handle._run_coro, name=handle.name)

src/anyio/abc/_tasks.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,20 @@
2525
PosArgsT = TypeVarTuple("PosArgsT")
2626

2727

28+
def get_coro_name(coro: Coroutine[Any, Any, object], override: object = None) -> str:
29+
if override is not None:
30+
return str(override)
31+
32+
try:
33+
cr_frame = coro.cr_frame # type: ignore[attr-defined]
34+
module = cr_frame.f_globals["__name__"]
35+
except (AttributeError, KeyError):
36+
module = None
37+
38+
qualname = getattr(coro, "__qualname__", None)
39+
return ".".join([x for x in (module, qualname) if x])
40+
41+
2842
def get_callable_name(func: Callable, override: object = None) -> str:
2943
if override is not None:
3044
return str(override)

tests/test_taskgroups.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2145,14 +2145,14 @@ async def taskfunc(x: int, y: int) -> int:
21452145

21462146
assert re.match(
21472147
r"<TaskHandle pending "
2148-
r"name='TestCreateTask.test_return_value.<locals>.taskfunc' "
2148+
r"name='tests.test_taskgroups.TestCreateTask.test_return_value.<locals>.taskfunc' "
21492149
r"coro=<coroutine object(.+)>>",
21502150
repr(handle),
21512151
)
21522152
assert await handle == 6
21532153
assert re.match(
21542154
r"<TaskHandle finished "
2155-
r"name='TestCreateTask.test_return_value.<locals>.taskfunc' "
2155+
r"name='tests.test_taskgroups.TestCreateTask.test_return_value.<locals>.taskfunc' "
21562156
r"coro=<coroutine object(.+)>>",
21572157
repr(handle),
21582158
)
@@ -2179,7 +2179,7 @@ async def taskfunc() -> NoReturn:
21792179

21802180
assert re.match(
21812181
r"<TaskHandle failed "
2182-
r"name='TestCreateTask.test_exception.<locals>.taskfunc' "
2182+
r"name='tests.test_taskgroups.TestCreateTask.test_exception.<locals>.taskfunc' "
21832183
r"coro=<coroutine object(.+)>",
21842184
repr(handle),
21852185
)
@@ -2202,7 +2202,7 @@ async def main() -> None:
22022202
assert handle.status is TaskHandle.Status.FAILED
22032203
assert re.match(
22042204
r"<TaskHandle failed "
2205-
r"name='TestCreateTask.test_base_exception.<locals>.taskfunc' "
2205+
r"name='tests.test_taskgroups.TestCreateTask.test_base_exception.<locals>.taskfunc' "
22062206
r"coro=<coroutine object(.+)>",
22072207
repr(handle),
22082208
)
@@ -2237,7 +2237,7 @@ async def taskfunc() -> None:
22372237
assert handle.status is TaskHandle.Status.CANCELLING
22382238
assert re.match(
22392239
r"<TaskHandle cancelling "
2240-
r"name='TestCreateTask.test_cancel.<locals>.taskfunc' "
2240+
r"name='tests.test_taskgroups.TestCreateTask.test_cancel.<locals>.taskfunc' "
22412241
r"coro=<coroutine object(.+)>>",
22422242
repr(handle),
22432243
)
@@ -2259,7 +2259,7 @@ async def taskfunc() -> None:
22592259
assert task_started
22602260
assert re.match(
22612261
r"<TaskHandle cancelled "
2262-
r"name='TestCreateTask.test_cancel.<locals>.taskfunc' "
2262+
r"name='tests.test_taskgroups.TestCreateTask.test_cancel.<locals>.taskfunc' "
22632263
r"coro=<coroutine object(.+)>>",
22642264
repr(handle),
22652265
)
@@ -2284,13 +2284,16 @@ async def taskfunc() -> str | None:
22842284
handle = tg.create_task(taskfunc())
22852285
assert re.match(
22862286
r"<TaskHandle pending "
2287-
r"name='TestCreateTask.test_task_name_default.<locals>.taskfunc' "
2287+
r"name='tests.test_taskgroups.TestCreateTask.test_task_name_default.<locals>.taskfunc' "
22882288
r"coro=<coroutine object(.+)>>",
22892289
repr(handle),
22902290
)
22912291
assert await handle == handle.name
22922292

2293-
assert handle.name == "TestCreateTask.test_task_name_default.<locals>.taskfunc"
2293+
assert (
2294+
handle.name
2295+
== "tests.test_taskgroups.TestCreateTask.test_task_name_default.<locals>.taskfunc"
2296+
)
22942297

22952298
async def test_task_name_custom_name(self) -> None:
22962299
async def taskfunc() -> None:
@@ -2326,11 +2329,7 @@ async def genfunc(x: int, y: int) -> AsyncGenerator[int, None]:
23262329

23272330
async with create_task_group() as tg:
23282331
async with aclosing(genfunc(3, 5)) as g:
2329-
if create_task:
2330-
handle = tg.create_task(g.asend(None))
2331-
assert handle.name.startswith("<async_generator_asend object at ")
2332-
else:
2333-
handle = tg.start_soon(g.asend, None)
2334-
assert handle.name == "async_generator.asend"
2332+
handle = tg.start_soon(g.asend, None)
2333+
assert handle.name == "async_generator.asend"
23352334

23362335
assert await handle == 8

0 commit comments

Comments
 (0)