Skip to content

Commit a5bf963

Browse files
authored
chore(integrations): internalize get_version, patch, and unpatch for all integrations [3.0] (#11916)
Requires: [chore: avoids using deprecated modules in tests and log injection [3.0 prep]](#11835). Follow up to: #11918 This change internalizes the following functions: - `ddtrace.contrib.<integration_name>.patch()` - `ddtrace.contrib.<integration_name>.unpatch()` - `ddtrace.contrib.<integration_name>.get_version()` This change also internalizes all integrations that only expose `patch()`, `unpatch()`, and `get_version()` functions. ## Checklist - [x] PR author has checked that all the criteria below are met - The PR description includes an overview of the change - The PR description articulates the motivation for the change - The change includes tests OR the PR description describes a testing strategy - The PR description notes risks associated with the change, if any - Newly-added code is easy to change - The change follows the [library release note guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html) - The change includes or references documentation updates if necessary - Backport labels are set (if [applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)) ## Reviewer Checklist - [x] Reviewer has checked that all the criteria below are met - Title is accurate - All changes are related to the pull request's stated goal - Avoids breaking [API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces) changes - Testing strategy adequately addresses listed risks - Newly-added code is easy to change - Release note makes sense to a user of the library - If necessary, author has acknowledged and discussed the performance implications of this PR as reported in the benchmarks PR comment - Backport labels are set in a manner that is consistent with the [release branch maintenance policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)
1 parent a1b7b9d commit a5bf963

File tree

171 files changed

+1538
-1521
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

171 files changed

+1538
-1521
lines changed

ddtrace/_monkey.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,13 @@ def _on_import_factory(module, prefix="ddtrace.contrib", raise_errors=True, patc
176176

177177
def on_import(hook):
178178
# Import and patch module
179-
path = "%s.%s" % (prefix, module)
180179
try:
181-
imported_module = importlib.import_module(path)
180+
try:
181+
imported_module = importlib.import_module("%s.internal.%s.patch" % (prefix, module))
182+
except ImportError:
183+
# Some integrations do not have an internal patch module, so we use the public one
184+
# FIXME: This is a temporary solution until we refactor the patching logic.
185+
imported_module = importlib.import_module("%s.%s" % (prefix, module))
182186
imported_module.patch()
183187
if hasattr(imported_module, "patch_submodules"):
184188
imported_module.patch_submodules(patch_indicator)
@@ -204,7 +208,8 @@ def on_import(hook):
204208
telemetry.telemetry_writer.add_integration(
205209
name, True, PATCH_MODULES.get(module) is True, "", version=v
206210
)
207-
else:
211+
elif hasattr(imported_module, "get_version"):
212+
# TODO: Ensure every integration defines either get_version or get_versions in their patch.py module
208213
version = imported_module.get_version()
209214
telemetry.telemetry_writer.add_integration(
210215
module, True, PATCH_MODULES.get(module) is True, "", version=version

ddtrace/_trace/trace_handlers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from ddtrace.constants import SPAN_MEASURED_KEY
2323
from ddtrace.contrib import trace_utils
2424
from ddtrace.contrib.internal.botocore.constants import BOTOCORE_STEPFUNCTIONS_INPUT_KEY
25-
from ddtrace.contrib.trace_utils import _set_url_tag
25+
from ddtrace.contrib.internal.trace_utils import _set_url_tag
2626
from ddtrace.ext import SpanKind
2727
from ddtrace.ext import db
2828
from ddtrace.ext import http

ddtrace/_trace/utils_redis.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from ddtrace.constants import SPAN_KIND
1111
from ddtrace.constants import SPAN_MEASURED_KEY
1212
from ddtrace.contrib import trace_utils
13-
from ddtrace.contrib.redis_utils import _extract_conn_tags
13+
from ddtrace.contrib.internal.redis_utils import _extract_conn_tags
1414
from ddtrace.ext import SpanKind
1515
from ddtrace.ext import SpanTypes
1616
from ddtrace.ext import db

ddtrace/appsec/_handlers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
from ddtrace.appsec._asm_request_context import get_blocked
77
from ddtrace.appsec._constants import SPAN_DATA_NAMES
88
from ddtrace.contrib import trace_utils
9-
from ddtrace.contrib.trace_utils import _get_request_header_user_agent
10-
from ddtrace.contrib.trace_utils import _set_url_tag
9+
from ddtrace.contrib.internal.trace_utils import _get_request_header_user_agent
10+
from ddtrace.contrib.internal.trace_utils import _set_url_tag
1111
from ddtrace.ext import SpanTypes
1212
from ddtrace.ext import http
1313
from ddtrace.internal import core

ddtrace/appsec/_processor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ def get_rules() -> str:
101101

102102

103103
def _set_headers(span: Span, headers: Any, kind: str, only_asm_enabled: bool = False) -> None:
104-
from ddtrace.contrib.trace_utils import _normalize_tag_name
104+
from ddtrace.contrib.internal.trace_utils import _normalize_tag_name
105105

106106
for k in headers:
107107
if isinstance(k, tuple):
@@ -218,7 +218,7 @@ def rasp_sqli_enabled(self) -> bool:
218218
return WAF_DATA_NAMES.SQLI_ADDRESS in self._addresses_to_keep
219219

220220
def on_span_start(self, span: Span) -> None:
221-
from ddtrace.contrib import trace_utils
221+
from ddtrace.contrib.internal import trace_utils
222222

223223
if not hasattr(self, "_ddwaf"):
224224
self.delayed_init()

ddtrace/appsec/_trace_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from ddtrace.appsec._constants import LOGIN_EVENTS_MODE
1212
from ddtrace.appsec._constants import WAF_ACTIONS
1313
from ddtrace.appsec._utils import _hash_user_id
14-
from ddtrace.contrib.trace_utils import set_user
14+
from ddtrace.contrib.internal.trace_utils import set_user
1515
from ddtrace.ext import SpanTypes
1616
from ddtrace.ext import user
1717
from ddtrace.internal import core

ddtrace/appsec/_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def parse_response_body(raw_body):
2222

2323
from ddtrace.appsec import _asm_request_context
2424
from ddtrace.appsec._constants import SPAN_DATA_NAMES
25-
from ddtrace.contrib.trace_utils import _get_header_value_case_insensitive
25+
from ddtrace.contrib.internal.trace_utils import _get_header_value_case_insensitive
2626

2727
if not raw_body:
2828
return

ddtrace/contrib/__init__.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,73 @@
11
from ddtrace._trace import trace_handlers # noqa:F401
2+
from ddtrace.internal.utils.deprecations import DDTraceDeprecationWarning
23
from ddtrace.internal.utils.importlib import func_name # noqa:F401
34
from ddtrace.internal.utils.importlib import module_name # noqa:F401
45
from ddtrace.internal.utils.importlib import require_modules # noqa:F401
6+
from ddtrace.vendor.debtcollector import deprecate
7+
8+
9+
def __getattr__(name):
10+
if name in (
11+
"aiohttp",
12+
"asgi",
13+
"bottle",
14+
"celery",
15+
"cherrypy",
16+
"falcon",
17+
"flask_cache",
18+
"pylibmc",
19+
"pyramid",
20+
"requests",
21+
"sqlalchemy",
22+
"wsgi",
23+
"trace_utils",
24+
"internal",
25+
):
26+
# following packages/modules are not deprecated and will not be removed in 3.0
27+
pass
28+
elif name in ("trace_handlers", "func_name", "module_name", "require_modules"):
29+
# the following attributes are exposed in ddtrace.contrib.__init__ and should be
30+
# removed in v3.0
31+
deprecate(
32+
("ddtrace.contrib.%s is deprecated" % name),
33+
category=DDTraceDeprecationWarning,
34+
removal_version="3.0.0",
35+
)
36+
elif name in ("aiobotocore", "httplib", "kombu", "snowflake", "sqlalchemy", "tornado", "urllib3"):
37+
# following integrations are not enabled by default and require a unique deprecation message
38+
deprecate(
39+
f"ddtrace.contrib.{name} is deprecated",
40+
message="Avoid using this package directly. "
41+
f"Set DD_TRACE_{name.upper()}_ENABLED=true and use ``ddtrace.auto`` or the "
42+
"``ddtrace-run`` command to enable and configure this integration.",
43+
category=DDTraceDeprecationWarning,
44+
removal_version="3.0.0",
45+
)
46+
elif name in ("redis_utils", "trace_utils_redis", "trace_utils_async"):
47+
deprecate(
48+
f"The ddtrace.contrib.{name} module is deprecated",
49+
message="Import from ``ddtrace.contrib.trace_utils`` instead.",
50+
category=DDTraceDeprecationWarning,
51+
removal_version="3.0.0",
52+
)
53+
elif name == "flask_login":
54+
deprecate(
55+
"""The flask_login integration is deprecated and will be deleted.
56+
We recommend customers to switch to manual instrumentation.
57+
https://docs.datadoghq.com/security/application_security/threats/add-user-info/?tab=loginsuccess&code-lang=python#adding-business-logic-information-login-success-login-failure-any-business-logic-to-traces
58+
""",
59+
message="",
60+
category=DDTraceDeprecationWarning,
61+
)
62+
else:
63+
deprecate(
64+
f"ddtrace.contrib.{name} is deprecated",
65+
message="Avoid using this package directly. "
66+
f"Use ``import ddtrace.auto`` or the ``ddtrace-run`` command to enable and configure {name}.",
67+
category=DDTraceDeprecationWarning,
68+
removal_version="3.0.0",
69+
)
70+
71+
if name in globals():
72+
return globals()[name]
73+
raise AttributeError("%s has no attribute %s", __name__, name)

ddtrace/contrib/aiobotocore/__init__.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@
3535
_w.simplefilter("ignore", DeprecationWarning)
3636
from . import patch as _ # noqa: F401, I001
3737

38-
# Expose public methods
39-
from ddtrace.contrib.internal.aiobotocore.patch import get_version
40-
from ddtrace.contrib.internal.aiobotocore.patch import patch
4138

42-
43-
__all__ = ["patch", "get_version"]
39+
from ddtrace.contrib.internal.aiobotocore.patch import get_version # noqa: F401
40+
from ddtrace.contrib.internal.aiobotocore.patch import patch # noqa: F401

ddtrace/contrib/aiohttp/__init__.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,25 @@ async def home_handler(request):
9494
_w.simplefilter("ignore", DeprecationWarning)
9595
from . import patch as _ # noqa: F401, I001
9696
from ddtrace.contrib.internal.aiohttp.middlewares import trace_app
97-
from ddtrace.contrib.internal.aiohttp.patch import get_version
97+
from ddtrace.contrib.internal.aiohttp.patch import get_version # noqa: F401
98+
from ddtrace.contrib.internal.aiohttp.patch import patch # noqa: F401
99+
from ddtrace.contrib.internal.aiohttp.patch import unpatch # noqa: F401
100+
from ddtrace.internal.utils.deprecations import DDTraceDeprecationWarning
101+
from ddtrace.vendor.debtcollector import deprecate
98102

99-
# Expose public methods
100-
from ddtrace.contrib.internal.aiohttp.patch import patch
101-
from ddtrace.contrib.internal.aiohttp.patch import unpatch
102103

104+
def __getattr__(name):
105+
if name in ("patch", "get_version", "unpatch"):
106+
deprecate(
107+
("%s.%s is deprecated" % (__name__, name)),
108+
message="Use ``import ddtrace.auto`` or the ``ddtrace-run`` command to configure this integration.",
109+
category=DDTraceDeprecationWarning,
110+
removal_version="3.0.0",
111+
)
103112

104-
__all__ = ["patch", "unpatch", "trace_app", "get_version"]
113+
if name in globals():
114+
return globals()[name]
115+
raise AttributeError("%s has no attribute %s", __name__, name)
116+
117+
118+
__all__ = ["trace_app"]

ddtrace/contrib/aiohttp_jinja2/__init__.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@
2323
_w.simplefilter("ignore", DeprecationWarning)
2424
from . import patch as _ # noqa: F401, I001
2525

26-
from ddtrace.contrib.internal.aiohttp_jinja2.patch import get_version
27-
from ddtrace.contrib.internal.aiohttp_jinja2.patch import patch
28-
from ddtrace.contrib.internal.aiohttp_jinja2.patch import unpatch
29-
30-
31-
__all__ = ["patch", "unpatch", "get_version"]
26+
from ddtrace.contrib.internal.aiohttp_jinja2.patch import get_version # noqa: F401
27+
from ddtrace.contrib.internal.aiohttp_jinja2.patch import patch # noqa: F401
28+
from ddtrace.contrib.internal.aiohttp_jinja2.patch import unpatch # noqa: F401

ddtrace/contrib/aiomysql/__init__.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,6 @@
4545
_w.simplefilter("ignore", DeprecationWarning)
4646
from . import patch as _ # noqa: F401, I001
4747

48-
from ddtrace.contrib.internal.aiomysql.patch import get_version
49-
from ddtrace.contrib.internal.aiomysql.patch import patch
50-
from ddtrace.contrib.internal.aiomysql.patch import unpatch
51-
52-
53-
__all__ = ["patch", "unpatch", "get_version"]
48+
from ddtrace.contrib.internal.aiomysql.patch import get_version # noqa: F401
49+
from ddtrace.contrib.internal.aiomysql.patch import patch # noqa: F401
50+
from ddtrace.contrib.internal.aiomysql.patch import unpatch # noqa: F401

ddtrace/contrib/aiopg/__init__.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,5 @@
2626
_w.simplefilter("ignore", DeprecationWarning)
2727
from . import patch as _ # noqa: F401, I001
2828

29-
from ddtrace.contrib.internal.aiopg.patch import get_version
30-
from ddtrace.contrib.internal.aiopg.patch import patch
31-
32-
33-
__all__ = ["patch", "get_version"]
29+
from ddtrace.contrib.internal.aiopg.patch import get_version # noqa: F401
30+
from ddtrace.contrib.internal.aiopg.patch import patch # noqa: F401

ddtrace/contrib/aioredis/__init__.py

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,3 @@
1-
from ddtrace.internal.utils.deprecations import DDTraceDeprecationWarning
2-
from ddtrace.vendor.debtcollector import deprecate
3-
4-
5-
deprecate(
6-
"The aioredis integration is deprecated.",
7-
message="Please use the redis integration with redis>=4.2.0 instead.",
8-
category=DDTraceDeprecationWarning,
9-
)
101
"""
112
The aioredis integration instruments aioredis requests. Version 1.3 and above are fully
123
supported.
@@ -75,11 +66,8 @@
7566
with _w.catch_warnings():
7667
_w.simplefilter("ignore", DeprecationWarning)
7768
# Required to allow users to import from `ddtrace.contrib.aioredis.patch` directly
78-
from . import patch as _ # noqa: F401, I001
79-
80-
from ddtrace.contrib.internal.aioredis.patch import get_version # noqa: E402
81-
from ddtrace.contrib.internal.aioredis.patch import patch # noqa: E402
82-
from ddtrace.contrib.internal.aioredis.patch import unpatch # noqa: E402
83-
69+
from . import patch as _ # noqa: I001,F401
8470

85-
__all__ = ["patch", "unpatch", "get_version"]
71+
from ddtrace.contrib.internal.aioredis.patch import get_version # noqa: F401
72+
from ddtrace.contrib.internal.aioredis.patch import patch # noqa: F401
73+
from ddtrace.contrib.internal.aioredis.patch import unpatch # noqa: F401

ddtrace/contrib/algoliasearch/__init__.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,6 @@
3131
_w.simplefilter("ignore", DeprecationWarning)
3232
from . import patch as _ # noqa: F401, I001
3333

34-
from ddtrace.contrib.internal.algoliasearch.patch import get_version
35-
from ddtrace.contrib.internal.algoliasearch.patch import patch
36-
from ddtrace.contrib.internal.algoliasearch.patch import unpatch
37-
38-
39-
__all__ = ["patch", "unpatch", "get_version"]
34+
from ddtrace.contrib.internal.algoliasearch.patch import get_version # noqa: F401
35+
from ddtrace.contrib.internal.algoliasearch.patch import patch # noqa: F401
36+
from ddtrace.contrib.internal.algoliasearch.patch import unpatch # noqa: F401

ddtrace/contrib/anthropic/__init__.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,6 @@
9191
_w.simplefilter("ignore", DeprecationWarning)
9292
from . import patch as _ # noqa: F401, I001
9393

94-
from ddtrace.contrib.internal.anthropic.patch import get_version
95-
from ddtrace.contrib.internal.anthropic.patch import patch
96-
from ddtrace.contrib.internal.anthropic.patch import unpatch
97-
98-
99-
__all__ = ["patch", "unpatch", "get_version"]
94+
from ddtrace.contrib.internal.anthropic.patch import get_version # noqa: F401
95+
from ddtrace.contrib.internal.anthropic.patch import patch # noqa: F401
96+
from ddtrace.contrib.internal.anthropic.patch import unpatch # noqa: F401

ddtrace/contrib/aredis/__init__.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,5 @@ async def example():
7575
_w.simplefilter("ignore", DeprecationWarning)
7676
from . import patch as _ # noqa: F401, I001
7777

78-
from ddtrace.contrib.internal.aredis.patch import get_version
79-
from ddtrace.contrib.internal.aredis.patch import patch
80-
81-
82-
__all__ = ["patch", "get_version"]
78+
from ddtrace.contrib.internal.aredis.patch import get_version # noqa: F401
79+
from ddtrace.contrib.internal.aredis.patch import patch # noqa: F401

ddtrace/contrib/asgi/__init__.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,24 @@ def handle_request(scope, send):
5757

5858

5959
from ddtrace.contrib.internal.asgi.middleware import TraceMiddleware
60-
from ddtrace.contrib.internal.asgi.middleware import get_version
60+
from ddtrace.contrib.internal.asgi.middleware import get_version # noqa: F401
6161
from ddtrace.contrib.internal.asgi.middleware import span_from_scope
62+
from ddtrace.internal.utils.deprecations import DDTraceDeprecationWarning
63+
from ddtrace.vendor.debtcollector import deprecate
6264

6365

64-
__all__ = ["TraceMiddleware", "span_from_scope", "get_version"]
66+
def __getattr__(name):
67+
if name in ("get_version",):
68+
deprecate(
69+
("%s.%s is deprecated" % (__name__, name)),
70+
message="Use ``import ddtrace.auto`` or the ``ddtrace-run`` command to configure this integration.",
71+
category=DDTraceDeprecationWarning,
72+
removal_version="3.0.0",
73+
)
74+
75+
if name in globals():
76+
return globals()[name]
77+
raise AttributeError("%s has no attribute %s", __name__, name)
78+
79+
80+
__all__ = ["TraceMiddleware", "span_from_scope"]

ddtrace/contrib/asyncio/__init__.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,20 @@
33
of concurrent execution of ``asyncio.Task``.
44
"""
55
# Required to allow users to import from `ddtrace.contrib.asyncio.patch` directly
6-
# Expose public methods
6+
77
import warnings as _w # noqa:E402
88

99

1010
with _w.catch_warnings():
1111
_w.simplefilter("ignore", DeprecationWarning)
1212
from . import patch as _ # noqa: F401, I001
1313
from ddtrace._trace.provider import DefaultContextProvider
14-
from ddtrace.contrib.internal.asyncio.helpers import ensure_future
15-
from ddtrace.contrib.internal.asyncio.helpers import run_in_executor
16-
from ddtrace.contrib.internal.asyncio.helpers import set_call_context
17-
from ddtrace.contrib.internal.asyncio.patch import get_version
18-
from ddtrace.contrib.internal.asyncio.patch import patch
14+
from ddtrace.contrib.internal.asyncio.helpers import ensure_future # noqa: F401
15+
from ddtrace.contrib.internal.asyncio.helpers import run_in_executor # noqa: F401
16+
from ddtrace.contrib.internal.asyncio.helpers import set_call_context # noqa: F401
17+
from ddtrace.contrib.internal.asyncio.patch import get_version # noqa: F401
18+
from ddtrace.contrib.internal.asyncio.patch import patch # noqa: F401
1919
from ddtrace.contrib.internal.asyncio.patch import unpatch # noqa: F401
2020

2121

2222
context_provider = DefaultContextProvider()
23-
24-
25-
__all__ = ["context_provider", "set_call_context", "ensure_future", "run_in_executor", "patch", "get_version"]

ddtrace/contrib/asyncpg/__init__.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,6 @@
5353
_w.simplefilter("ignore", DeprecationWarning)
5454
from . import patch as _ # noqa: F401, I001
5555

56-
from ddtrace.contrib.internal.asyncpg.patch import get_version
57-
from ddtrace.contrib.internal.asyncpg.patch import patch
58-
from ddtrace.contrib.internal.asyncpg.patch import unpatch
59-
60-
61-
__all__ = ["patch", "unpatch", "get_version"]
56+
from ddtrace.contrib.internal.asyncpg.patch import get_version # noqa: F401
57+
from ddtrace.contrib.internal.asyncpg.patch import patch # noqa: F401
58+
from ddtrace.contrib.internal.asyncpg.patch import unpatch # noqa: F401

ddtrace/contrib/avro/__init__.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@
1515
~~~~~~~~~~~~~
1616
1717
"""
18-
# Expose public methods
19-
from ..internal.avro.patch import get_version
20-
from ..internal.avro.patch import patch
2118

22-
23-
__all__ = ["patch", "get_version"]
19+
from ..internal.avro.patch import get_version # noqa: F401
20+
from ..internal.avro.patch import patch # noqa: F401

0 commit comments

Comments
 (0)