chore(py3.15): peripheral compat for profiling, logging, and appsec - #19267
chore(py3.15): peripheral compat for profiling, logging, and appsec#19267vlad-scherbich wants to merge 5 commits into
Conversation
|
32359ee to
9e90c28
Compare
BenchmarksBenchmark execution time: 2026-08-21 09:11:14 Comparing candidate commit 107d29b in PR branch Found 0 performance improvements and 9 performance regressions! Performance is the same for 609 metrics, 10 unstable metrics.
|
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9e90c28497
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
This PR is part of the Python 3.15 compatibility/parity effort (#17809), focusing on making import-time behavior degrade gracefully (rather than crashing) for profiling, bytecode wrapping/injection dependents, logging, and AppSec-related instrumentation, with targeted tests and documentation updates.
Changes:
- Make wrapping/bytecode-injection modules importable on Python 3.15+ while keeping runtime APIs (
wrap(),inject_hook(), etc.) raisingNotImplementedErrorwhen invoked. - Add profiling “availability” gating (
is_available/failure_msg) soddtrace.profiling.autocan warn and skip instead of crashing when native extensions are missing. - Add/adjust tests and docs for the new degradation behavior; suppress Python 3.15+
logging.__version__deprecation warnings.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/smoke_test.py | Restores environment safely and asserts product plugin loading doesn’t silently fail during WAF smoke test. |
| tests/profiling/test_profiler.py | Adds subprocess test ensuring ddtrace.profiling.auto import degrades when profiling is unavailable. |
| tests/internal/test_py315_import_degrade.py | New tests validating import-time degradation and expected NotImplementedError behavior on 3.15+. |
| docs/basic_usage.rst | Documents profiling availability checks and auto-import warning/skip behavior. |
| ddtrace/profiling/bootstrap/sitecustomize.py | Gates profiler startup on ddtrace.profiling.is_available, warning and returning when unavailable. |
| ddtrace/profiling/init.py | Implements is_available / failure_msg pattern and provides a stub Profiler that raises on construction when unavailable. |
| ddtrace/internal/wrapping/generators.py | Avoids import-time failure on 3.15+ and raises NotImplementedError at runtime for unsupported wrapping. |
| ddtrace/internal/wrapping/context.py | Same degradation pattern for wrapping context on 3.15+. |
| ddtrace/internal/wrapping/asyncs.py | Same degradation pattern for async wrapping on 3.15+. |
| ddtrace/internal/wrapping/init.py | Adds runtime guards so wrap() / wrap_bytecode() raise NotImplementedError on 3.15+. |
| ddtrace/internal/module.py | Adds _exec_lazy_init fallback to support @lazy module initialization without bytecode wrapping on 3.15+. |
| ddtrace/internal/compat.py | Introduces centralized “next unsupported Python” constants/messages used by wrapping/injection code. |
| ddtrace/internal/bytecode_injection/init.py | Avoids import-time failure on 3.15+ and raises NotImplementedError at runtime for injection APIs. |
| ddtrace/debugging/_function/store.py | Adjusts restore logic, but currently introduces a missing API usage/import (see comments). |
| ddtrace/contrib/internal/logging/patch.py | Suppresses Python 3.15+ DeprecationWarning when reading logging.__version__. |
| ddtrace/appsec/sca/_instrumenter.py | Refactors first-instruction-line detection to handle 3.13+/3.15 differences consistently. |
Suppressed comments (1)
ddtrace/debugging/_function/store.py:103
- This Python 3.15+ branch calls
eject_all_hooks(function), butbytecode_injectiondoes not provide that API, so this will fail at runtime if reached. Additionally, hook injection is already disabled for Python >= 3.15 (bothinject_hookandinject_hooksraiseNotImplementedError), so this cleanup block should be unnecessary when restoring functions.
if PY >= (3, 15):
functions: list[FunctionType] = list(self._code_map)
for function in functions:
eject_all_hooks(function)
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Codeowners resolved asResolved from the full PR diff against |
Circular import analysis
|
Dependency direction analysis
|
Wheel smoke tests fail on 3.15 because wrapping raises at import and profiling.auto loads native extensions that are not built yet. Defer the wrapping error until wrap is actually used, and disable the profiler when those extensions are missing.
Part of the #17849 split (PR 6/6). # Conflicts: # ddtrace/appsec/sca/_instrumenter.py # ddtrace/profiling/__init__.py # ddtrace/profiling/bootstrap/sitecustomize.py
# Conflicts: # ddtrace/profiling/__init__.py
Add the missing bytecode_injection helper so store.py imports succeed on all Python versions, and use NEXT_PY_VERSION_INFO for the restore guard.
29c8910 to
107d29b
Compare
| def eject_all_hooks(f: FunctionType) -> None: | ||
| """Remove every line hook registered for *f*. | ||
|
|
||
| No-op while bytecode injection is unavailable on this Python version. | ||
| """ | ||
| return None |
prev: #19724 (on
main) | next: #19269Summary
Peripheral compat for profiling, logging, and appsec on 3.15, plus
eject_all_hooksforFunctionStore.restore_all. Import degrade is already onmainvia #19724 — this PR is the remaining Tier B prep before native work.Test plan
Tracker