Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 0 additions & 22 deletions .riot/requirements/1353fd0.txt

This file was deleted.

22 changes: 0 additions & 22 deletions .riot/requirements/1540a76.txt

This file was deleted.

28 changes: 28 additions & 0 deletions .riot/requirements/18417b5.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
# pip-compile --allow-unsafe --no-annotate .riot/requirements/18417b5.in
#
attrs==25.4.0
backports-asyncio-runner==1.2.0
coverage[toml]==7.12.0
exceptiongroup==1.3.0
httpretty==1.1.4
hypothesis==6.45.0
iniconfig==2.3.0
mock==5.2.0
msgpack==1.1.2
opentracing==2.4.0
packaging==25.0
pluggy==1.6.0
py-cpuinfo==9.0.0
pygments==2.19.2
pytest==9.0.1
pytest-asyncio==1.3.0
pytest-benchmark==5.2.3
pytest-cov==7.0.0
pytest-mock==3.15.1
sortedcontainers==2.4.0
tomli==2.3.0
typing-extensions==4.15.0
25 changes: 25 additions & 0 deletions .riot/requirements/18569c9.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --allow-unsafe --no-annotate .riot/requirements/18569c9.in
#
attrs==25.4.0
coverage[toml]==7.12.0
httpretty==1.1.4
hypothesis==6.45.0
iniconfig==2.3.0
mock==5.2.0
msgpack==1.1.2
opentracing==2.4.0
packaging==25.0
pluggy==1.6.0
py-cpuinfo==9.0.0
pygments==2.19.2
pytest==9.0.1
pytest-asyncio==1.3.0
pytest-benchmark==5.2.3
pytest-cov==7.0.0
pytest-mock==3.15.1
sortedcontainers==2.4.0
typing-extensions==4.15.0
28 changes: 28 additions & 0 deletions .riot/requirements/191f37c.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#
# This file is autogenerated by pip-compile with Python 3.9
# by the following command:
#
# pip-compile --allow-unsafe --no-annotate .riot/requirements/191f37c.in
#
attrs==25.4.0
backports-asyncio-runner==1.2.0
coverage[toml]==7.10.7
exceptiongroup==1.3.0
httpretty==1.1.4
hypothesis==6.45.0
iniconfig==2.1.0
mock==5.2.0
msgpack==1.1.2
opentracing==2.4.0
packaging==25.0
pluggy==1.6.0
py-cpuinfo==9.0.0
pygments==2.19.2
pytest==8.4.2
pytest-asyncio==1.2.0
pytest-benchmark==5.2.3
pytest-cov==7.0.0
pytest-mock==3.15.1
sortedcontainers==2.4.0
tomli==2.3.0
typing-extensions==4.15.0
25 changes: 25 additions & 0 deletions .riot/requirements/197e9b6.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#
# This file is autogenerated by pip-compile with Python 3.13
# by the following command:
#
# pip-compile --allow-unsafe --no-annotate .riot/requirements/197e9b6.in
#
attrs==25.4.0
coverage[toml]==7.12.0
httpretty==1.1.4
hypothesis==6.45.0
iniconfig==2.3.0
mock==5.2.0
msgpack==1.1.2
opentracing==2.4.0
packaging==25.0
pluggy==1.6.0
py-cpuinfo==9.0.0
pygments==2.19.2
pytest==9.0.1
pytest-asyncio==1.3.0
pytest-benchmark==5.2.3
pytest-cov==7.0.0
pytest-mock==3.15.1
sortedcontainers==2.4.0
typing-extensions==4.15.0
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,24 @@
# This file is autogenerated by pip-compile with Python 3.14
# by the following command:
#
# pip-compile --allow-unsafe --no-annotate .riot/requirements/1d9ed4a.in
# pip-compile --allow-unsafe --no-annotate .riot/requirements/1a30fec.in
#
attrs==25.3.0
coverage[toml]==7.10.5
attrs==25.4.0
coverage[toml]==7.12.0
httpretty==1.1.4
hypothesis==6.45.0
iniconfig==2.1.0
iniconfig==2.3.0
mock==5.2.0
msgpack==1.1.1
msgpack==1.1.2
opentracing==2.4.0
packaging==25.0
pluggy==1.6.0
py-cpuinfo==9.0.0
pygments==2.19.2
pytest==8.4.1
pytest-asyncio==1.1.0
pytest-cov==6.2.1
pytest-mock==3.14.1
pytest==9.0.1
pytest-asyncio==1.3.0
pytest-benchmark==5.2.3
pytest-cov==7.0.0
pytest-mock==3.15.1
sortedcontainers==2.4.0
typing-extensions==4.15.0
24 changes: 0 additions & 24 deletions .riot/requirements/1a9b995.txt

This file was deleted.

22 changes: 0 additions & 22 deletions .riot/requirements/2644218.txt

This file was deleted.

25 changes: 25 additions & 0 deletions .riot/requirements/278c26c.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#
# This file is autogenerated by pip-compile with Python 3.12
# by the following command:
#
# pip-compile --allow-unsafe --no-annotate .riot/requirements/278c26c.in
#
attrs==25.4.0
coverage[toml]==7.12.0
httpretty==1.1.4
hypothesis==6.45.0
iniconfig==2.3.0
mock==5.2.0
msgpack==1.1.2
opentracing==2.4.0
packaging==25.0
pluggy==1.6.0
py-cpuinfo==9.0.0
pygments==2.19.2
pytest==9.0.1
pytest-asyncio==1.3.0
pytest-benchmark==5.2.3
pytest-cov==7.0.0
pytest-mock==3.15.1
sortedcontainers==2.4.0
typing-extensions==4.15.0
24 changes: 0 additions & 24 deletions .riot/requirements/5c95c1a.txt

This file was deleted.

5 changes: 4 additions & 1 deletion ddtrace/debugging/_function/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,10 @@ def resolve(self) -> FullyNamedFunction:
msg = "Cannot resolve pair with no code object"
raise ValueError(msg)

if self.function is not None:
# Check that the function we have cached is not a wrapper layer that
# has been unwrapped. In this case we need to resolve the new function
# from the code object.
if (_ := self.function) is not None and _.__name__ != "<unwrapped>":
return cast(FullyNamedFunction, self.function)

code = self.code
Expand Down
13 changes: 10 additions & 3 deletions ddtrace/debugging/_origin/span.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from ddtrace.internal.packages import is_user_code
from ddtrace.internal.safety import _isinstance
from ddtrace.internal.settings.code_origin import config as co_config
from ddtrace.internal.wrapping.context import WrappingContext
from ddtrace.internal.wrapping.context import LazyWrappingContext
from ddtrace.trace import Span


Expand Down Expand Up @@ -111,7 +111,14 @@ class EntrySpanLocation:
probe: EntrySpanProbe


class EntrySpanWrappingContext(WrappingContext):
class EntrySpanWrappingContext(LazyWrappingContext):
"""Entry span wrapping context.

This context is lazy to avoid paid any upfront instrumentation costs for
large functions that might not get invoked. Instead, the actual wrapping
will be performed on the first invocation.
"""

__enabled__ = False
__priority__ = 199

Expand Down Expand Up @@ -227,7 +234,7 @@ def instrument_view(cls, f: t.Union[FunctionType, MethodType]) -> None:

_f = t.cast(FunctionType, f)
if not EntrySpanWrappingContext.is_wrapped(_f):
log.debug("Patching entrypoint %r for code origin", f)
log.debug("Lazy wrapping entrypoint %r for code origin", f)
EntrySpanWrappingContext(cls.__uploader__, _f).wrap()

@classmethod
Expand Down
3 changes: 0 additions & 3 deletions ddtrace/internal/utils/inspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@ def undecorated(f: FunctionType, name: str, path: Path) -> FunctionType:
def match(g):
return g.__code__.co_name == name and resolved_code_origin(g.__code__) == path

if _isinstance(f, FunctionType) and match(f):
return f

seen_functions = {f}
q = deque([f]) # FIFO: use popleft and append

Expand Down
7 changes: 7 additions & 0 deletions ddtrace/internal/wrapping/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,13 @@ def unwrap(wf, wrapper):
# current one.
f = cast(FunctionType, wf)
f.__code__ = inner.__code__

# Mark the function as unwrapped via its name. There might be references
# to this function elsewhere and this would signal that the function has
# been unwrapped and that another function object is referencing the
# original code object.
inner.__name__ = "<unwrapped>"

try:
# Update the link to the next layer.
inner_wf = cast(WrappedFunction, inner)
Expand Down
18 changes: 18 additions & 0 deletions ddtrace/internal/wrapping/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,11 +394,29 @@ def wrap(self) -> None:
if self._trampoline is not None:
return

# If the function is already universally wrapped so it's less expensive
# to do the normal wrapping.
if _UniversalWrappingContext.is_wrapped(self.__wrapped__):
super().wrap()
return

def trampoline(_, args, kwargs):
with tl:
f = t.cast(WrappedFunction, self.__wrapped__)
if is_wrapped_with(self.__wrapped__, trampoline):
# If the wrapped function was instrumented with a
# wrapping context before the first invocation we need
# to carry that over to the original function when we
# remove the trampoline.
try:
inner = f.__dd_wrapped__
except AttributeError:
inner = None
f = unwrap(f, trampoline)
try:
f.__dd_context_wrapped__ = inner.__dd_context_wrapped__
except AttributeError:
pass
super(LazyWrappingContext, self).wrap()
return f(*args, **kwargs)

Expand Down
1 change: 1 addition & 0 deletions riotfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,7 @@ def select_pys(min_version: str = MIN_PYTHON_VERSION, max_version: str = MAX_PYT
"httpretty": latest,
"typing-extensions": latest,
"pytest-asyncio": latest,
"pytest-benchmark": latest,
},
pys=select_pys(),
),
Expand Down
Loading
Loading