Skip to content

Commit c293c8a

Browse files
P403n1x87github-actions[bot]
authored andcommitted
fix(debugger): max match in probe file resolution (#15143)
## Description We change the probe source file path matching logic to return the longest matching path instead of the first result. This deals with cases where sources with the same name can be found on different entries of the Python path. ## Testing <!-- Describe your testing strategy or note what tests are included --> (cherry picked from commit 953ef8b)
1 parent 1e5d096 commit c293c8a

File tree

3 files changed

+32
-3
lines changed

3 files changed

+32
-3
lines changed

ddtrace/debugging/_probe/model.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,8 @@ def _resolve_source_file(_path: str) -> Optional[Path]:
4141
if path.is_file():
4242
return path.resolve()
4343

44-
for relpath in (path.relative_to(_) for _ in path.parents):
45-
resolved_path = _resolve(relpath)
46-
if resolved_path is not None:
44+
for relpath in (path.relative_to(_) for _ in reversed(path.parents)):
45+
if (resolved_path := _resolve(relpath)) is not None:
4746
return resolved_path
4847

4948
return None
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
fixes:
3+
- |
4+
dynamic instrumentation: fix issue with line probes matching the wrong
5+
source file when multiple source files from different Python path entries
6+
share the same name.

tests/debugging/probe/test_model.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from pathlib import Path
2+
import sys
23

34
from ddtrace.debugging._expressions import DDExpression
45
from ddtrace.debugging._expressions import dd_compile
@@ -57,3 +58,26 @@ def test_probe_hash():
5758
)
5859

5960
assert hash(probe)
61+
62+
63+
def test_resolve_source_file_same_filename_on_different_paths(tmp_path: Path):
64+
"""
65+
Test that if we have sources with the same name along different Python
66+
paths, we resolve to the longest matching path.
67+
"""
68+
# Setup the file system for the test
69+
(p := tmp_path / "a" / "b").mkdir(parents=True)
70+
(q := tmp_path / "c" / "b").mkdir(parents=True)
71+
72+
(fp := p / "test_model.py").touch()
73+
(fq := q / "test_model.py").touch()
74+
75+
# Patch the python path
76+
original_pythonpath = sys.path
77+
78+
try:
79+
sys.path = [str(tmp_path / "c"), str(tmp_path)]
80+
assert (r := _resolve_source_file("a/b/test_model.py")) is not None and r.resolve() == fp.resolve(), r
81+
assert (r := _resolve_source_file("c/b/test_model.py")) is not None and r.resolve() == fq.resolve(), r
82+
finally:
83+
sys.path = original_pythonpath

0 commit comments

Comments
 (0)