Skip to content

Commit 25a7a37

Browse files
fix: fix the python detector regex + tests [backport 3.17] (#15078)
Backport 2a69e20 from #15068 to 3.17. ## Description - Fix the Python Detector regex so it also detects paths ending with the major version number (/foo/bar/python3). - Use `re.compile`. - Add tests. ## Testing - Add a new test for positive and negative matches of the Python Detector. Signed-off-by: Juanjo Alvarez <juanjo.alvarezmartinez@datadoghq.com> Co-authored-by: Juanjo Alvarez Martinez <juanjo.alvarezmartinez@datadoghq.com>
1 parent 58542d4 commit 25a7a37

File tree

3 files changed

+43
-3
lines changed

3 files changed

+43
-3
lines changed

ddtrace/settings/_inferred_base_service.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ def __init__(self, environ: Dict[str, str]):
3636
# - Starts with an optional directory (anything before the last '/' or '')
3737
# - Ends with the expected command name, possibly followed by a version
3838
# - Ensures that it does not end with .py
39-
# - Match /python, /python3.7, etc.
40-
self.pattern = r"(^|/)(?!.*\.py$)(" + re.escape("python") + r"(\d+\.\d+)?$)"
39+
# - Match /python, /python3, /python3.7, etc.
40+
self.pattern = re.compile(r"(^|/)(?!.*\.py$)(" + re.escape("python") + r"(\d+(\.\d+)?)?$)")
4141

4242
def detect(self, args: List[str], skip_args_preceded_by_flags=True) -> Optional[ServiceMetadata]:
4343
"""
@@ -127,7 +127,7 @@ def find_nearest_top_level(self, fp: pathlib.Path) -> str:
127127

128128
def matches(self, command: str) -> bool:
129129
# Returns if the command matches the regex pattern for finding python executables / commands.
130-
return bool(re.search(self.pattern, command))
130+
return bool(self.pattern.search(command))
131131

132132

133133
def detect_service(args: List[str]) -> Optional[str]:
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
fixes:
3+
- |
4+
Fix the Python Detector regular expression so it also detects paths ending with only the major version number.

tests/internal/service_name/test_inferred_base_service.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import pytest
1010

11+
from ddtrace.settings._inferred_base_service import PythonDetector
1112
from ddtrace.settings._inferred_base_service import _module_exists
1213
from ddtrace.settings._inferred_base_service import detect_service
1314

@@ -240,3 +241,38 @@ def test_get_service(cmd, default, expected, testdir):
240241
)
241242

242243
assert "AssertionError" not in result.stderr, "AssertionError found in stderr"
244+
245+
246+
@pytest.mark.parametrize(
247+
"command,should_match,expected_capture",
248+
[
249+
("python", True, "python"),
250+
("python3", True, "python3"),
251+
("python3.11", True, "python3.11"),
252+
("/usr/local/bin/python", True, "/python"),
253+
("/usr/local/bin/python3", True, "/python3"),
254+
("/usr/local/bin/python3.11", True, "/python3.11"),
255+
("python2", True, "python2"),
256+
("python3.9", True, "python3.9"),
257+
("/python", True, "/python"),
258+
("/python3", True, "/python3"),
259+
("python.py", False, None), # Should not match .py files
260+
("/path/to/python.py", False, None), # Should not match .py files
261+
("not-python", False, None), # Should not match
262+
("pythonic", False, None), # Should not match
263+
],
264+
)
265+
def test_python_detector_pattern_matching(command, should_match, expected_capture):
266+
"""Test that the PythonDetector regex pattern correctly matches various Python executable formats."""
267+
detector = PythonDetector(dict(os.environ))
268+
269+
match = detector.pattern.search(command)
270+
271+
if should_match:
272+
assert match is not None, f"Expected '{command}' to match but it didn't"
273+
# The full match should contain the expected capture
274+
assert expected_capture in match.group(
275+
0
276+
), f"Expected capture '{expected_capture}' not found in match '{match.group(0)}'"
277+
else:
278+
assert match is None, f"Expected '{command}' not to match but it did: {match.group(0) if match else None}"

0 commit comments

Comments
 (0)