We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Problem with Popen arguments passed as map
Greetings!

I am having an issue when using the package `sorl.thumbnail` on a Django project. That package produces thumbnails from images using system installed programs (called engines.)

When `sorl.thumbnail` makes a `Popen` call here:

https://github.com/jazzband/sorl-thumbnail/blob/22ccd9781462a820f963f57018ad3dcef85053ed/sorl/thumbnail/engines/convert_engine.py#L57

The arguments that are received in your patched `Popen` are not being interpreted correctly. This is the suspect of the problem:

https://github.com/getsentry/sentry-python/blob/2c0a2ea96882adf69742bd7e79e588564ff5b85c/sentry_sdk/integrations/stdlib.py#L143

Arguments are handled in such a way that the original `popen` crashes when trying to access `args[0]`, as the `args` parameter is interpreted (or actually becomes) an empty list.

In my opinion, the problem arises because in `sorl.thumbnail` the arguments to `Popen` are passed to a `map` function first, so that a `map` object is what gets passed as arguments. I am not sure what's the effect of a `map` object being received in your `*a` of the patched `Popen`.

Here's the relevant part of the traceback I am getting:

```
File "/mnt/d/Proyectos/ginseng/.venv/lib/python3.6/site-packages/sorl/thumbnail/base.py", line 131, in get_thumbnail
    thumbnail)
  File "/mnt/d/Proyectos/ginseng/.venv/lib/python3.6/site-packages/sorl/thumbnail/base.py", line 164, in _create_thumbnail
    default.engine.write(image, options, thumbnail)
  File "/mnt/d/Proyectos/ginseng/.venv/lib/python3.6/site-packages/sorl/thumbnail/engines/convert_engine.py", line 57, in write
    p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  File "/mnt/d/Proyectos/ginseng/.venv/lib/python3.6/site-packages/sentry_sdk/integrations/stdlib.py", line 165, in sentry_patched_popen_init
    return old_popen_init(self, *a, **kw)
  File "/usr/lib/python3.6/subprocess.py", line 729, in __init__
    restore_signals, start_new_session)
  File "/usr/lib/python3.6/subprocess.py", line 1248, in _execute_child
    executable = args[0]
IndexError: list index out of range
```

If I remove the Sentry integration altogether from the Django project, `sorl.thumbnail` is able to effectively call `Popen` with the "mapped" arguments, and everything works.

Thanks in advance!

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sentry_sdk/integrations/stdlib.py`
Content:
```
1 import os
2 import subprocess
3 import sys
4 import platform
5 
6 from sentry_sdk.hub import Hub
7 from sentry_sdk.integrations import Integration
8 from sentry_sdk.scope import add_global_event_processor
9 from sentry_sdk.tracing import EnvironHeaders, record_http_request
10 
11 try:
12     from httplib import HTTPConnection  # type: ignore
13 except ImportError:
14     from http.client import HTTPConnection
15 
16 _RUNTIME_CONTEXT = {
17     "name": platform.python_implementation(),
18     "version": "%s.%s.%s" % (sys.version_info[:3]),
19     "build": sys.version,
20 }
21 
22 
23 class StdlibIntegration(Integration):
24     identifier = "stdlib"
25 
26     @staticmethod
27     def setup_once():
28         # type: () -> None
29         _install_httplib()
30         _install_subprocess()
31 
32         @add_global_event_processor
33         def add_python_runtime_context(event, hint):
34             if Hub.current.get_integration(StdlibIntegration) is not None:
35                 contexts = event.setdefault("contexts", {})
36                 if isinstance(contexts, dict) and "runtime" not in contexts:
37                     contexts["runtime"] = _RUNTIME_CONTEXT
38 
39             return event
40 
41 
42 def _install_httplib():
43     # type: () -> None
44     real_putrequest = HTTPConnection.putrequest
45     real_getresponse = HTTPConnection.getresponse
46 
47     def putrequest(self, method, url, *args, **kwargs):
48         hub = Hub.current
49         if hub.get_integration(StdlibIntegration) is None:
50             return real_putrequest(self, method, url, *args, **kwargs)
51 
52         host = self.host
53         port = self.port
54         default_port = self.default_port
55 
56         real_url = url
57         if not real_url.startswith(("http://", "https://")):
58             real_url = "%s://%s%s%s" % (
59                 default_port == 443 and "https" or "http",
60                 host,
61                 port != default_port and ":%s" % port or "",
62                 url,
63             )
64 
65         recorder = record_http_request(hub, real_url, method)
66         data_dict = recorder.__enter__()
67 
68         try:
69             rv = real_putrequest(self, method, url, *args, **kwargs)
70 
71             for key, value in hub.iter_trace_propagation_headers():
72                 self.putheader(key, value)
73         except Exception:
74             recorder.__exit__(*sys.exc_info())
75             raise
76 
77         self._sentrysdk_recorder = recorder
78         self._sentrysdk_data_dict = data_dict
79 
80         return rv
81 
82     def getresponse(self, *args, **kwargs):
83         recorder = getattr(self, "_sentrysdk_recorder", None)
84 
85         if recorder is None:
86             return real_getresponse(self, *args, **kwargs)
87 
88         data_dict = getattr(self, "_sentrysdk_data_dict", None)
89 
90         try:
91             rv = real_getresponse(self, *args, **kwargs)
92 
93             if data_dict is not None:
94                 data_dict["httplib_response"] = rv
95                 data_dict["status_code"] = rv.status
96                 data_dict["reason"] = rv.reason
97         except TypeError:
98             # python-requests provokes a typeerror to discover py3 vs py2 differences
99             #
100             # > TypeError("getresponse() got an unexpected keyword argument 'buffering'")
101             raise
102         except Exception:
103             recorder.__exit__(*sys.exc_info())
104             raise
105         else:
106             recorder.__exit__(None, None, None)
107 
108         return rv
109 
110     HTTPConnection.putrequest = putrequest
111     HTTPConnection.getresponse = getresponse
112 
113 
114 def _init_argument(args, kwargs, name, position, setdefault_callback=None):
115     """
116     given (*args, **kwargs) of a function call, retrieve (and optionally set a
117     default for) an argument by either name or position.
118 
119     This is useful for wrapping functions with complex type signatures and
120     extracting a few arguments without needing to redefine that function's
121     entire type signature.
122     """
123 
124     if name in kwargs:
125         rv = kwargs[name]
126         if rv is None and setdefault_callback is not None:
127             rv = kwargs[name] = setdefault_callback()
128     elif position < len(args):
129         rv = args[position]
130         if rv is None and setdefault_callback is not None:
131             rv = args[position] = setdefault_callback()
132     else:
133         rv = setdefault_callback and setdefault_callback()
134         if rv is not None:
135             kwargs[name] = rv
136 
137     return rv
138 
139 
140 def _install_subprocess():
141     old_popen_init = subprocess.Popen.__init__
142 
143     def sentry_patched_popen_init(self, *a, **kw):
144         hub = Hub.current
145         if hub.get_integration(StdlibIntegration) is None:
146             return old_popen_init(self, *a, **kw)
147 
148         # do not setdefault! args is required by Popen, doing setdefault would
149         # make invalid calls valid
150         args = _init_argument(a, kw, "args", 0) or []
151         cwd = _init_argument(a, kw, "cwd", 10)
152 
153         env = None
154 
155         for k, v in hub.iter_trace_propagation_headers():
156             if env is None:
157                 env = _init_argument(a, kw, "env", 11, lambda: dict(os.environ))
158             env["SUBPROCESS_" + k.upper().replace("-", "_")] = v
159 
160         with hub.span(op="subprocess", description=" ".join(map(str, args))) as span:
161             span.set_tag("subprocess.cwd", cwd)
162 
163             return old_popen_init(self, *a, **kw)
164 
165     subprocess.Popen.__init__ = sentry_patched_popen_init  # type: ignore
166 
167 
168 def get_subprocess_traceparent_headers():
169     return EnvironHeaders(os.environ, prefix="SUBPROCESS_")
170
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/sentry_sdk/integrations/stdlib.py b/sentry_sdk/integrations/stdlib.py
--- a/sentry_sdk/integrations/stdlib.py
+++ b/sentry_sdk/integrations/stdlib.py
@@ -7,12 +7,15 @@
 from sentry_sdk.integrations import Integration
 from sentry_sdk.scope import add_global_event_processor
 from sentry_sdk.tracing import EnvironHeaders, record_http_request
+from sentry_sdk.utils import capture_internal_exceptions, safe_repr
+
 
 try:
     from httplib import HTTPConnection  # type: ignore
 except ImportError:
     from http.client import HTTPConnection
 
+
 _RUNTIME_CONTEXT = {
     "name": platform.python_implementation(),
     "version": "%s.%s.%s" % (sys.version_info[:3]),
@@ -123,14 +126,18 @@
 
     if name in kwargs:
         rv = kwargs[name]
-        if rv is None and setdefault_callback is not None:
-            rv = kwargs[name] = setdefault_callback()
+        if setdefault_callback is not None:
+            rv = setdefault_callback(rv)
+        if rv is not None:
+            kwargs[name] = rv
     elif position < len(args):
         rv = args[position]
-        if rv is None and setdefault_callback is not None:
-            rv = args[position] = setdefault_callback()
+        if setdefault_callback is not None:
+            rv = setdefault_callback(rv)
+        if rv is not None:
+            args[position] = rv
     else:
-        rv = setdefault_callback and setdefault_callback()
+        rv = setdefault_callback and setdefault_callback(None)
         if rv is not None:
             kwargs[name] = rv
 
@@ -145,20 +152,37 @@
         if hub.get_integration(StdlibIntegration) is None:
             return old_popen_init(self, *a, **kw)
 
-        # do not setdefault! args is required by Popen, doing setdefault would
-        # make invalid calls valid
+        # Convert from tuple to list to be able to set values.
+        a = list(a)
+
         args = _init_argument(a, kw, "args", 0) or []
-        cwd = _init_argument(a, kw, "cwd", 10)
+        cwd = _init_argument(a, kw, "cwd", 9)
+
+        # if args is not a list or tuple (and e.g. some iterator instead),
+        # let's not use it at all. There are too many things that can go wrong
+        # when trying to collect an iterator into a list and setting that list
+        # into `a` again.
+        #
+        # Also invocations where `args` is not a sequence are not actually
+        # legal. They just happen to work under CPython.
+        description = None
+
+        if isinstance(args, (list, tuple)) and len(args) < 100:
+            with capture_internal_exceptions():
+                description = " ".join(map(str, args))
+
+        if description is None:
+            description = safe_repr(args)
 
         env = None
 
         for k, v in hub.iter_trace_propagation_headers():
             if env is None:
-                env = _init_argument(a, kw, "env", 11, lambda: dict(os.environ))
+                env = _init_argument(a, kw, "env", 10, lambda x: dict(x or os.environ))
             env["SUBPROCESS_" + k.upper().replace("-", "_")] = v
 
-        with hub.span(op="subprocess", description=" ".join(map(str, args))) as span:
-            span.set_tag("subprocess.cwd", cwd)
+        with hub.span(op="subprocess", description=description) as span:
+            span.set_data("subprocess.cwd", cwd)
 
             return old_popen_init(self, *a, **kw)

{"golden_diff": "diff --git a/sentry_sdk/integrations/stdlib.py b/sentry_sdk/integrations/stdlib.py\n--- a/sentry_sdk/integrations/stdlib.py\n+++ b/sentry_sdk/integrations/stdlib.py\n@@ -7,12 +7,15 @@\n from sentry_sdk.integrations import Integration\n from sentry_sdk.scope import add_global_event_processor\n from sentry_sdk.tracing import EnvironHeaders, record_http_request\n+from sentry_sdk.utils import capture_internal_exceptions, safe_repr\n+\n \n try:\n     from httplib import HTTPConnection  # type: ignore\n except ImportError:\n     from http.client import HTTPConnection\n \n+\n _RUNTIME_CONTEXT = {\n     \"name\": platform.python_implementation(),\n     \"version\": \"%s.%s.%s\" % (sys.version_info[:3]),\n@@ -123,14 +126,18 @@\n \n     if name in kwargs:\n         rv = kwargs[name]\n-        if rv is None and setdefault_callback is not None:\n-            rv = kwargs[name] = setdefault_callback()\n+        if setdefault_callback is not None:\n+            rv = setdefault_callback(rv)\n+        if rv is not None:\n+            kwargs[name] = rv\n     elif position < len(args):\n         rv = args[position]\n-        if rv is None and setdefault_callback is not None:\n-            rv = args[position] = setdefault_callback()\n+        if setdefault_callback is not None:\n+            rv = setdefault_callback(rv)\n+        if rv is not None:\n+            args[position] = rv\n     else:\n-        rv = setdefault_callback and setdefault_callback()\n+        rv = setdefault_callback and setdefault_callback(None)\n         if rv is not None:\n             kwargs[name] = rv\n \n@@ -145,20 +152,37 @@\n         if hub.get_integration(StdlibIntegration) is None:\n             return old_popen_init(self, *a, **kw)\n \n-        # do not setdefault! args is required by Popen, doing setdefault would\n-        # make invalid calls valid\n+        # Convert from tuple to list to be able to set values.\n+        a = list(a)\n+\n         args = _init_argument(a, kw, \"args\", 0) or []\n-        cwd = _init_argument(a, kw, \"cwd\", 10)\n+        cwd = _init_argument(a, kw, \"cwd\", 9)\n+\n+        # if args is not a list or tuple (and e.g. some iterator instead),\n+        # let's not use it at all. There are too many things that can go wrong\n+        # when trying to collect an iterator into a list and setting that list\n+        # into `a` again.\n+        #\n+        # Also invocations where `args` is not a sequence are not actually\n+        # legal. They just happen to work under CPython.\n+        description = None\n+\n+        if isinstance(args, (list, tuple)) and len(args) < 100:\n+            with capture_internal_exceptions():\n+                description = \" \".join(map(str, args))\n+\n+        if description is None:\n+            description = safe_repr(args)\n \n         env = None\n \n         for k, v in hub.iter_trace_propagation_headers():\n             if env is None:\n-                env = _init_argument(a, kw, \"env\", 11, lambda: dict(os.environ))\n+                env = _init_argument(a, kw, \"env\", 10, lambda x: dict(x or os.environ))\n             env[\"SUBPROCESS_\" + k.upper().replace(\"-\", \"_\")] = v\n \n-        with hub.span(op=\"subprocess\", description=\" \".join(map(str, args))) as span:\n-            span.set_tag(\"subprocess.cwd\", cwd)\n+        with hub.span(op=\"subprocess\", description=description) as span:\n+            span.set_data(\"subprocess.cwd\", cwd)\n \n             return old_popen_init(self, *a, **kw)\n", "issue": "Problem with Popen arguments passed as map\nGreetings!\r\n\r\nI am having an issue when using the package `sorl.thumbnail` on a Django project. That package produces thumbnails from images using system installed programs (called engines.)\r\n\r\nWhen `sorl.thumbnail` makes a `Popen` call here:\r\n\r\nhttps://github.com/jazzband/sorl-thumbnail/blob/22ccd9781462a820f963f57018ad3dcef85053ed/sorl/thumbnail/engines/convert_engine.py#L57\r\n\r\nThe arguments that are received in your patched `Popen` are not being interpreted correctly. This is the suspect of the problem:\r\n\r\nhttps://github.com/getsentry/sentry-python/blob/2c0a2ea96882adf69742bd7e79e588564ff5b85c/sentry_sdk/integrations/stdlib.py#L143\r\n\r\nArguments are handled in such a way that the original `popen` crashes when trying to access `args[0]`, as the `args` parameter is interpreted (or actually becomes) an empty list.\r\n\r\nIn my opinion, the problem arises because in `sorl.thumbnail` the arguments to `Popen` are passed to a `map` function first, so that a `map` object is what gets passed as arguments. I am not sure what's the effect of a `map` object being received in your `*a` of the patched `Popen`.\r\n\r\nHere's the relevant part of the traceback I am getting:\r\n\r\n```\r\nFile \"/mnt/d/Proyectos/ginseng/.venv/lib/python3.6/site-packages/sorl/thumbnail/base.py\", line 131, in get_thumbnail\r\n    thumbnail)\r\n  File \"/mnt/d/Proyectos/ginseng/.venv/lib/python3.6/site-packages/sorl/thumbnail/base.py\", line 164, in _create_thumbnail\r\n    default.engine.write(image, options, thumbnail)\r\n  File \"/mnt/d/Proyectos/ginseng/.venv/lib/python3.6/site-packages/sorl/thumbnail/engines/convert_engine.py\", line 57, in write\r\n    p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)\r\n  File \"/mnt/d/Proyectos/ginseng/.venv/lib/python3.6/site-packages/sentry_sdk/integrations/stdlib.py\", line 165, in sentry_patched_popen_init\r\n    return old_popen_init(self, *a, **kw)\r\n  File \"/usr/lib/python3.6/subprocess.py\", line 729, in __init__\r\n    restore_signals, start_new_session)\r\n  File \"/usr/lib/python3.6/subprocess.py\", line 1248, in _execute_child\r\n    executable = args[0]\r\nIndexError: list index out of range\r\n```\r\n\r\nIf I remove the Sentry integration altogether from the Django project, `sorl.thumbnail` is able to effectively call `Popen` with the \"mapped\" arguments, and everything works.\r\n\r\nThanks in advance!\n", "before_files": [{"content": "import os\nimport subprocess\nimport sys\nimport platform\n\nfrom sentry_sdk.hub import Hub\nfrom sentry_sdk.integrations import Integration\nfrom sentry_sdk.scope import add_global_event_processor\nfrom sentry_sdk.tracing import EnvironHeaders, record_http_request\n\ntry:\n    from httplib import HTTPConnection  # type: ignore\nexcept ImportError:\n    from http.client import HTTPConnection\n\n_RUNTIME_CONTEXT = {\n    \"name\": platform.python_implementation(),\n    \"version\": \"%s.%s.%s\" % (sys.version_info[:3]),\n    \"build\": sys.version,\n}\n\n\nclass StdlibIntegration(Integration):\n    identifier = \"stdlib\"\n\n    @staticmethod\n    def setup_once():\n        # type: () -> None\n        _install_httplib()\n        _install_subprocess()\n\n        @add_global_event_processor\n        def add_python_runtime_context(event, hint):\n            if Hub.current.get_integration(StdlibIntegration) is not None:\n                contexts = event.setdefault(\"contexts\", {})\n                if isinstance(contexts, dict) and \"runtime\" not in contexts:\n                    contexts[\"runtime\"] = _RUNTIME_CONTEXT\n\n            return event\n\n\ndef _install_httplib():\n    # type: () -> None\n    real_putrequest = HTTPConnection.putrequest\n    real_getresponse = HTTPConnection.getresponse\n\n    def putrequest(self, method, url, *args, **kwargs):\n        hub = Hub.current\n        if hub.get_integration(StdlibIntegration) is None:\n            return real_putrequest(self, method, url, *args, **kwargs)\n\n        host = self.host\n        port = self.port\n        default_port = self.default_port\n\n        real_url = url\n        if not real_url.startswith((\"http://\", \"https://\")):\n            real_url = \"%s://%s%s%s\" % (\n                default_port == 443 and \"https\" or \"http\",\n                host,\n                port != default_port and \":%s\" % port or \"\",\n                url,\n            )\n\n        recorder = record_http_request(hub, real_url, method)\n        data_dict = recorder.__enter__()\n\n        try:\n            rv = real_putrequest(self, method, url, *args, **kwargs)\n\n            for key, value in hub.iter_trace_propagation_headers():\n                self.putheader(key, value)\n        except Exception:\n            recorder.__exit__(*sys.exc_info())\n            raise\n\n        self._sentrysdk_recorder = recorder\n        self._sentrysdk_data_dict = data_dict\n\n        return rv\n\n    def getresponse(self, *args, **kwargs):\n        recorder = getattr(self, \"_sentrysdk_recorder\", None)\n\n        if recorder is None:\n            return real_getresponse(self, *args, **kwargs)\n\n        data_dict = getattr(self, \"_sentrysdk_data_dict\", None)\n\n        try:\n            rv = real_getresponse(self, *args, **kwargs)\n\n            if data_dict is not None:\n                data_dict[\"httplib_response\"] = rv\n                data_dict[\"status_code\"] = rv.status\n                data_dict[\"reason\"] = rv.reason\n        except TypeError:\n            # python-requests provokes a typeerror to discover py3 vs py2 differences\n            #\n            # > TypeError(\"getresponse() got an unexpected keyword argument 'buffering'\")\n            raise\n        except Exception:\n            recorder.__exit__(*sys.exc_info())\n            raise\n        else:\n            recorder.__exit__(None, None, None)\n\n        return rv\n\n    HTTPConnection.putrequest = putrequest\n    HTTPConnection.getresponse = getresponse\n\n\ndef _init_argument(args, kwargs, name, position, setdefault_callback=None):\n    \"\"\"\n    given (*args, **kwargs) of a function call, retrieve (and optionally set a\n    default for) an argument by either name or position.\n\n    This is useful for wrapping functions with complex type signatures and\n    extracting a few arguments without needing to redefine that function's\n    entire type signature.\n    \"\"\"\n\n    if name in kwargs:\n        rv = kwargs[name]\n        if rv is None and setdefault_callback is not None:\n            rv = kwargs[name] = setdefault_callback()\n    elif position < len(args):\n        rv = args[position]\n        if rv is None and setdefault_callback is not None:\n            rv = args[position] = setdefault_callback()\n    else:\n        rv = setdefault_callback and setdefault_callback()\n        if rv is not None:\n            kwargs[name] = rv\n\n    return rv\n\n\ndef _install_subprocess():\n    old_popen_init = subprocess.Popen.__init__\n\n    def sentry_patched_popen_init(self, *a, **kw):\n        hub = Hub.current\n        if hub.get_integration(StdlibIntegration) is None:\n            return old_popen_init(self, *a, **kw)\n\n        # do not setdefault! args is required by Popen, doing setdefault would\n        # make invalid calls valid\n        args = _init_argument(a, kw, \"args\", 0) or []\n        cwd = _init_argument(a, kw, \"cwd\", 10)\n\n        env = None\n\n        for k, v in hub.iter_trace_propagation_headers():\n            if env is None:\n                env = _init_argument(a, kw, \"env\", 11, lambda: dict(os.environ))\n            env[\"SUBPROCESS_\" + k.upper().replace(\"-\", \"_\")] = v\n\n        with hub.span(op=\"subprocess\", description=\" \".join(map(str, args))) as span:\n            span.set_tag(\"subprocess.cwd\", cwd)\n\n            return old_popen_init(self, *a, **kw)\n\n    subprocess.Popen.__init__ = sentry_patched_popen_init  # type: ignore\n\n\ndef get_subprocess_traceparent_headers():\n    return EnvironHeaders(os.environ, prefix=\"SUBPROCESS_\")\n", "path": "sentry_sdk/integrations/stdlib.py"}], "after_files": [{"content": "import os\nimport subprocess\nimport sys\nimport platform\n\nfrom sentry_sdk.hub import Hub\nfrom sentry_sdk.integrations import Integration\nfrom sentry_sdk.scope import add_global_event_processor\nfrom sentry_sdk.tracing import EnvironHeaders, record_http_request\nfrom sentry_sdk.utils import capture_internal_exceptions, safe_repr\n\n\ntry:\n    from httplib import HTTPConnection  # type: ignore\nexcept ImportError:\n    from http.client import HTTPConnection\n\n\n_RUNTIME_CONTEXT = {\n    \"name\": platform.python_implementation(),\n    \"version\": \"%s.%s.%s\" % (sys.version_info[:3]),\n    \"build\": sys.version,\n}\n\n\nclass StdlibIntegration(Integration):\n    identifier = \"stdlib\"\n\n    @staticmethod\n    def setup_once():\n        # type: () -> None\n        _install_httplib()\n        _install_subprocess()\n\n        @add_global_event_processor\n        def add_python_runtime_context(event, hint):\n            if Hub.current.get_integration(StdlibIntegration) is not None:\n                contexts = event.setdefault(\"contexts\", {})\n                if isinstance(contexts, dict) and \"runtime\" not in contexts:\n                    contexts[\"runtime\"] = _RUNTIME_CONTEXT\n\n            return event\n\n\ndef _install_httplib():\n    # type: () -> None\n    real_putrequest = HTTPConnection.putrequest\n    real_getresponse = HTTPConnection.getresponse\n\n    def putrequest(self, method, url, *args, **kwargs):\n        hub = Hub.current\n        if hub.get_integration(StdlibIntegration) is None:\n            return real_putrequest(self, method, url, *args, **kwargs)\n\n        host = self.host\n        port = self.port\n        default_port = self.default_port\n\n        real_url = url\n        if not real_url.startswith((\"http://\", \"https://\")):\n            real_url = \"%s://%s%s%s\" % (\n                default_port == 443 and \"https\" or \"http\",\n                host,\n                port != default_port and \":%s\" % port or \"\",\n                url,\n            )\n\n        recorder = record_http_request(hub, real_url, method)\n        data_dict = recorder.__enter__()\n\n        try:\n            rv = real_putrequest(self, method, url, *args, **kwargs)\n\n            for key, value in hub.iter_trace_propagation_headers():\n                self.putheader(key, value)\n        except Exception:\n            recorder.__exit__(*sys.exc_info())\n            raise\n\n        self._sentrysdk_recorder = recorder\n        self._sentrysdk_data_dict = data_dict\n\n        return rv\n\n    def getresponse(self, *args, **kwargs):\n        recorder = getattr(self, \"_sentrysdk_recorder\", None)\n\n        if recorder is None:\n            return real_getresponse(self, *args, **kwargs)\n\n        data_dict = getattr(self, \"_sentrysdk_data_dict\", None)\n\n        try:\n            rv = real_getresponse(self, *args, **kwargs)\n\n            if data_dict is not None:\n                data_dict[\"httplib_response\"] = rv\n                data_dict[\"status_code\"] = rv.status\n                data_dict[\"reason\"] = rv.reason\n        except TypeError:\n            # python-requests provokes a typeerror to discover py3 vs py2 differences\n            #\n            # > TypeError(\"getresponse() got an unexpected keyword argument 'buffering'\")\n            raise\n        except Exception:\n            recorder.__exit__(*sys.exc_info())\n            raise\n        else:\n            recorder.__exit__(None, None, None)\n\n        return rv\n\n    HTTPConnection.putrequest = putrequest\n    HTTPConnection.getresponse = getresponse\n\n\ndef _init_argument(args, kwargs, name, position, setdefault_callback=None):\n    \"\"\"\n    given (*args, **kwargs) of a function call, retrieve (and optionally set a\n    default for) an argument by either name or position.\n\n    This is useful for wrapping functions with complex type signatures and\n    extracting a few arguments without needing to redefine that function's\n    entire type signature.\n    \"\"\"\n\n    if name in kwargs:\n        rv = kwargs[name]\n        if setdefault_callback is not None:\n            rv = setdefault_callback(rv)\n        if rv is not None:\n            kwargs[name] = rv\n    elif position < len(args):\n        rv = args[position]\n        if setdefault_callback is not None:\n            rv = setdefault_callback(rv)\n        if rv is not None:\n            args[position] = rv\n    else:\n        rv = setdefault_callback and setdefault_callback(None)\n        if rv is not None:\n            kwargs[name] = rv\n\n    return rv\n\n\ndef _install_subprocess():\n    old_popen_init = subprocess.Popen.__init__\n\n    def sentry_patched_popen_init(self, *a, **kw):\n        hub = Hub.current\n        if hub.get_integration(StdlibIntegration) is None:\n            return old_popen_init(self, *a, **kw)\n\n        # Convert from tuple to list to be able to set values.\n        a = list(a)\n\n        args = _init_argument(a, kw, \"args\", 0) or []\n        cwd = _init_argument(a, kw, \"cwd\", 9)\n\n        # if args is not a list or tuple (and e.g. some iterator instead),\n        # let's not use it at all. There are too many things that can go wrong\n        # when trying to collect an iterator into a list and setting that list\n        # into `a` again.\n        #\n        # Also invocations where `args` is not a sequence are not actually\n        # legal. They just happen to work under CPython.\n        description = None\n\n        if isinstance(args, (list, tuple)) and len(args) < 100:\n            with capture_internal_exceptions():\n                description = \" \".join(map(str, args))\n\n        if description is None:\n            description = safe_repr(args)\n\n        env = None\n\n        for k, v in hub.iter_trace_propagation_headers():\n            if env is None:\n                env = _init_argument(a, kw, \"env\", 10, lambda x: dict(x or os.environ))\n            env[\"SUBPROCESS_\" + k.upper().replace(\"-\", \"_\")] = v\n\n        with hub.span(op=\"subprocess\", description=description) as span:\n            span.set_data(\"subprocess.cwd\", cwd)\n\n            return old_popen_init(self, *a, **kw)\n\n    subprocess.Popen.__init__ = sentry_patched_popen_init  # type: ignore\n\n\ndef get_subprocess_traceparent_headers():\n    return EnvironHeaders(os.environ, prefix=\"SUBPROCESS_\")\n", "path": "sentry_sdk/integrations/stdlib.py"}]}