about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/sentry_sdk/integrations/threading.py
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/sentry_sdk/integrations/threading.py')
-rw-r--r--.venv/lib/python3.12/site-packages/sentry_sdk/integrations/threading.py121
1 files changed, 121 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/sentry_sdk/integrations/threading.py b/.venv/lib/python3.12/site-packages/sentry_sdk/integrations/threading.py
new file mode 100644
index 00000000..5de736e2
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sentry_sdk/integrations/threading.py
@@ -0,0 +1,121 @@
+import sys
+from functools import wraps
+from threading import Thread, current_thread
+
+import sentry_sdk
+from sentry_sdk.integrations import Integration
+from sentry_sdk.scope import use_isolation_scope, use_scope
+from sentry_sdk.utils import (
+    event_from_exception,
+    capture_internal_exceptions,
+    logger,
+    reraise,
+)
+
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from typing import Any
+    from typing import TypeVar
+    from typing import Callable
+    from typing import Optional
+
+    from sentry_sdk._types import ExcInfo
+
+    F = TypeVar("F", bound=Callable[..., Any])
+
+
+class ThreadingIntegration(Integration):
+    identifier = "threading"
+
+    def __init__(self, propagate_hub=None, propagate_scope=True):
+        # type: (Optional[bool], bool) -> None
+        if propagate_hub is not None:
+            logger.warning(
+                "Deprecated: propagate_hub is deprecated. This will be removed in the future."
+            )
+
+        # Note: propagate_hub did not have any effect on propagation of scope data
+        # scope data was always propagated no matter what the value of propagate_hub was
+        # This is why the default for propagate_scope is True
+
+        self.propagate_scope = propagate_scope
+
+        if propagate_hub is not None:
+            self.propagate_scope = propagate_hub
+
+    @staticmethod
+    def setup_once():
+        # type: () -> None
+        old_start = Thread.start
+
+        @wraps(old_start)
+        def sentry_start(self, *a, **kw):
+            # type: (Thread, *Any, **Any) -> Any
+            integration = sentry_sdk.get_client().get_integration(ThreadingIntegration)
+            if integration is None:
+                return old_start(self, *a, **kw)
+
+            if integration.propagate_scope:
+                isolation_scope = sentry_sdk.get_isolation_scope()
+                current_scope = sentry_sdk.get_current_scope()
+            else:
+                isolation_scope = None
+                current_scope = None
+
+            # Patching instance methods in `start()` creates a reference cycle if
+            # done in a naive way. See
+            # https://github.com/getsentry/sentry-python/pull/434
+            #
+            # In threading module, using current_thread API will access current thread instance
+            # without holding it to avoid a reference cycle in an easier way.
+            with capture_internal_exceptions():
+                new_run = _wrap_run(
+                    isolation_scope,
+                    current_scope,
+                    getattr(self.run, "__func__", self.run),
+                )
+                self.run = new_run  # type: ignore
+
+            return old_start(self, *a, **kw)
+
+        Thread.start = sentry_start  # type: ignore
+
+
+def _wrap_run(isolation_scope_to_use, current_scope_to_use, old_run_func):
+    # type: (Optional[sentry_sdk.Scope], Optional[sentry_sdk.Scope], F) -> F
+    @wraps(old_run_func)
+    def run(*a, **kw):
+        # type: (*Any, **Any) -> Any
+        def _run_old_run_func():
+            # type: () -> Any
+            try:
+                self = current_thread()
+                return old_run_func(self, *a, **kw)
+            except Exception:
+                reraise(*_capture_exception())
+
+        if isolation_scope_to_use is not None and current_scope_to_use is not None:
+            with use_isolation_scope(isolation_scope_to_use):
+                with use_scope(current_scope_to_use):
+                    return _run_old_run_func()
+        else:
+            return _run_old_run_func()
+
+    return run  # type: ignore
+
+
+def _capture_exception():
+    # type: () -> ExcInfo
+    exc_info = sys.exc_info()
+
+    client = sentry_sdk.get_client()
+    if client.get_integration(ThreadingIntegration) is not None:
+        event, hint = event_from_exception(
+            exc_info,
+            client_options=client.options,
+            mechanism={"type": "threading", "handled": False},
+        )
+        sentry_sdk.capture_event(event, hint=hint)
+
+    return exc_info