Skip to content

Commit 9a76e94

Browse files
improved type-annotation
1 parent f7e02f8 commit 9a76e94

4 files changed

Lines changed: 32 additions & 16 deletions

File tree

ddtrace/internal/wrapping/asyncs.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
from types import CodeType
2+
from typing import Final
3+
from typing import Optional
24

35
import bytecode as bc
46

@@ -28,9 +30,9 @@
2830
# return
2931
# -----------------------------------------------------------------------------
3032

31-
COROUTINE_ASSEMBLY = Assembly()
32-
ASYNC_GEN_ASSEMBLY = Assembly()
33-
ASYNC_HEAD_ASSEMBLY = None
33+
COROUTINE_ASSEMBLY: Final[Assembly] = Assembly()
34+
ASYNC_GEN_ASSEMBLY: Final[Assembly] = Assembly()
35+
ASYNC_HEAD_ASSEMBLY: Optional[Assembly] = None
3436

3537
if PY >= (3, 16):
3638
raise NotImplementedError("This version of CPython is not supported yet")

ddtrace/internal/wrapping/context.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@
7575
# __wrapped__ attribute. Context-specific values can be stored and retrieved
7676
# with the set and get methods.
7777

78-
CONTEXT_HEAD = Assembly()
79-
CONTEXT_RETURN = Assembly()
80-
CONTEXT_FOOT = Assembly()
78+
CONTEXT_HEAD: t.Final[Assembly] = Assembly()
79+
CONTEXT_RETURN: t.Final[Assembly] = Assembly()
80+
CONTEXT_FOOT: t.Final[Assembly] = Assembly()
8181

8282
if PY >= (3, 16):
8383
raise NotImplementedError("Python >= 3.16 is not supported yet")

ddtrace/internal/wrapping/generators.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
from types import CodeType
2+
from typing import Final
3+
from typing import Optional
24

35
import bytecode as bc
46

@@ -27,8 +29,8 @@
2729
# except StopIteration:
2830
# return
2931
# -----------------------------------------------------------------------------
30-
GENERATOR_ASSEMBLY = Assembly()
31-
GENERATOR_HEAD_ASSEMBLY = None
32+
GENERATOR_ASSEMBLY: Final[Assembly] = Assembly()
33+
GENERATOR_HEAD_ASSEMBLY: Optional[Assembly] = None
3234

3335
if PY >= (3, 16):
3436
raise NotImplementedError("This version of CPython is not supported yet")

ddtrace/profiling/_asyncio.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# -*- encoding: utf-8 -*-
22
from functools import partial
33
import sys
4-
import types
4+
from types import FunctionType
55
from types import ModuleType
66
import typing
77

@@ -29,6 +29,16 @@
2929
ASYNCIO_IMPORTED: bool = False
3030

3131

32+
# AIDEV-NOTE: Structural Protocols for introspected asyncio/uvloop classes. getattr() returns Any, so
33+
# these annotations document the contract we actually depend on rather than accepting any `type`.
34+
class _HasSetEventLoop(typing.Protocol):
35+
set_event_loop: typing.Callable[..., typing.Any]
36+
37+
38+
class _HasCreateTask(typing.Protocol):
39+
create_task: typing.Callable[..., typing.Any]
40+
41+
3242
def current_task() -> typing.Optional["asyncio.Task[typing.Any]"]:
3343
return None
3444

@@ -136,7 +146,7 @@ def _get_running_loop() -> typing.Optional["aio.AbstractEventLoop"]:
136146
# replaced — the policy hook won't exist. Use asyncio.run(loop_factory=...) instead.
137147
# See docs/contributing-profiling-new-cpython.rst for migration guidance.
138148
events_module: ModuleType = sys.modules["asyncio.events"]
139-
policy_class: typing.Optional[type]
149+
policy_class: typing.Optional[type[_HasSetEventLoop]]
140150
if sys.hexversion >= 0x030E0000:
141151
# Python 3.14+: Use _BaseDefaultEventLoopPolicy
142152
policy_class = getattr(events_module, "_BaseDefaultEventLoopPolicy", None)
@@ -292,10 +302,10 @@ def _(
292302
if sys.hexversion >= 0x030B0000: # Python 3.11+
293303
taskgroups_module: typing.Optional[ModuleType] = sys.modules.get("asyncio.taskgroups")
294304
if taskgroups_module is not None:
295-
taskgroup_class: typing.Optional[type] = getattr(taskgroups_module, "TaskGroup", None)
305+
taskgroup_class: typing.Optional[type[_HasCreateTask]] = getattr(taskgroups_module, "TaskGroup", None)
296306
if taskgroup_class is not None and hasattr(taskgroup_class, "create_task"):
297307

298-
@partial(wrap, taskgroup_class.create_task)
308+
@partial(wrap, typing.cast(FunctionType, taskgroup_class.create_task))
299309
def _(
300310
f: typing.Callable[..., "aio.Task[typing.Any]"],
301311
args: tuple[typing.Any, ...],
@@ -353,10 +363,12 @@ def _(uvloop: ModuleType) -> None:
353363
init_stack: bool = config.stack.enabled and stack.is_available
354364

355365
# Wrap uvloop.new_event_loop to track loops when they're created
356-
new_event_loop_func: typing.Optional[types.FunctionType] = getattr(uvloop, "new_event_loop", None)
366+
new_event_loop_func: typing.Optional[typing.Callable[..., "asyncio.AbstractEventLoop"]] = getattr(
367+
uvloop, "new_event_loop", None
368+
)
357369
if new_event_loop_func is not None:
358370

359-
@partial(wrap, new_event_loop_func)
371+
@partial(wrap, typing.cast(FunctionType, new_event_loop_func))
360372
def _(
361373
f: typing.Callable[..., "asyncio.AbstractEventLoop"],
362374
args: tuple[typing.Any, ...],
@@ -374,10 +386,10 @@ def _(
374386
return loop
375387

376388
# Wrap uvloop.EventLoopPolicy.set_event_loop for uvloop.install() + asyncio.run() pattern
377-
uvloop_policy_class: typing.Optional[type] = getattr(uvloop, "EventLoopPolicy", None)
389+
uvloop_policy_class: typing.Optional[type[_HasSetEventLoop]] = getattr(uvloop, "EventLoopPolicy", None)
378390
if uvloop_policy_class is not None and hasattr(uvloop_policy_class, "set_event_loop"):
379391

380-
@partial(wrap, uvloop_policy_class.set_event_loop)
392+
@partial(wrap, typing.cast(FunctionType, uvloop_policy_class.set_event_loop))
381393
def _(
382394
f: typing.Callable[..., typing.Any], args: tuple[typing.Any, ...], kwargs: dict[str, typing.Any]
383395
) -> typing.Any:

0 commit comments

Comments
 (0)