We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Incorrect types for patch() and patch_all() keyword arguments
### Which version of dd-trace-py are you using?
0.51.1

### Which version of pip are you using?

20.2.3

### Which version of the libraries are you using?

fastapi==0.63.0

### How can we reproduce your problem?

I have this line of code: `    ddtrace.patch(fastapi=True)`

And then in the command line I run `mypy project_dir`

### What is the result that you get?

`error: Argument "fastapi" to "patch" has incompatible type "bool"; expected "Dict[str, bool]"`

### What is the result that you expected?

No type errors


I believe this is because the type of the patch_modules parameter should be just `bool` and not `Dict[str, bool]` because it is a keyword arguments parameter (declared with **) for these two functions. See: https://www.python.org/dev/peps/pep-0484/#arbitrary-argument-lists-and-default-argument-values 

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `ddtrace/monkey.py`
Content:
```
1 """Patch libraries to be automatically instrumented.
2 
3 It can monkey patch supported standard libraries and third party modules.
4 A patched module will automatically report spans with its default configuration.
5 
6 A library instrumentation can be configured (for instance, to report as another service)
7 using Pin. For that, check its documentation.
8 """
9 import importlib
10 import os
11 import sys
12 import threading
13 from typing import Any
14 from typing import Callable
15 from typing import Dict
16 from typing import List
17 
18 from ddtrace.vendor.wrapt.importer import when_imported
19 
20 from .internal.logger import get_logger
21 from .settings import _config as config
22 from .utils import formats
23 from .utils.deprecation import deprecated
24 
25 
26 log = get_logger(__name__)
27 
28 # Default set of modules to automatically patch or not
29 PATCH_MODULES = {
30     "asyncio": True,
31     "boto": True,
32     "botocore": True,
33     "bottle": False,
34     "cassandra": True,
35     "celery": True,
36     "consul": True,
37     "django": True,
38     "elasticsearch": True,
39     "algoliasearch": True,
40     "futures": True,
41     "grpc": True,
42     "mongoengine": True,
43     "mysql": True,
44     "mysqldb": True,
45     "pymysql": True,
46     "mariadb": True,
47     "psycopg": True,
48     "pylibmc": True,
49     "pymemcache": True,
50     "pymongo": True,
51     "redis": True,
52     "rediscluster": True,
53     "requests": True,
54     "sanic": True,
55     "sqlalchemy": False,  # Prefer DB client instrumentation
56     "sqlite3": True,
57     "aiohttp": True,  # requires asyncio (Python 3.4+)
58     "aiopg": True,
59     "aiobotocore": False,
60     "httplib": False,
61     "urllib3": False,
62     "vertica": True,
63     "molten": True,
64     "jinja2": True,
65     "mako": True,
66     "flask": True,
67     "kombu": False,
68     "starlette": True,
69     # Ignore some web framework integrations that might be configured explicitly in code
70     "falcon": False,
71     "pylons": False,
72     "pyramid": False,
73     # Auto-enable logging if the environment variable DD_LOGS_INJECTION is true
74     "logging": config.logs_injection,
75     "pynamodb": True,
76     "pyodbc": True,
77     "fastapi": True,
78     "dogpile_cache": True,
79 }
80 
81 _LOCK = threading.Lock()
82 _PATCHED_MODULES = set()
83 
84 # Modules which are patched on first use
85 # DEV: These modules are patched when the user first imports them, rather than
86 #      explicitly importing and patching them on application startup `ddtrace.patch_all(module=True)`
87 # DEV: This ensures we do not patch a module until it is needed
88 # DEV: <contrib name> => <list of module names that trigger a patch>
89 _PATCH_ON_IMPORT = {
90     "aiohttp": ("aiohttp",),
91     "aiobotocore": ("aiobotocore",),
92     "celery": ("celery",),
93     "flask": ("flask",),
94     "gevent": ("gevent",),
95     "requests": ("requests",),
96     "botocore": ("botocore",),
97     "elasticsearch": (
98         "elasticsearch",
99         "elasticsearch2",
100         "elasticsearch5",
101         "elasticsearch6",
102         "elasticsearch7",
103     ),
104     "pynamodb": ("pynamodb",),
105 }
106 
107 
108 class PatchException(Exception):
109     """Wraps regular `Exception` class when patching modules"""
110 
111     pass
112 
113 
114 class ModuleNotFoundException(PatchException):
115     pass
116 
117 
118 def _on_import_factory(module, raise_errors=True):
119     # type: (str, bool) -> Callable[[Any], None]
120     """Factory to create an import hook for the provided module name"""
121 
122     def on_import(hook):
123         # Import and patch module
124         path = "ddtrace.contrib.%s" % module
125         try:
126             imported_module = importlib.import_module(path)
127         except ImportError:
128             if raise_errors:
129                 raise
130             log.error("failed to import ddtrace module %r when patching on import", path, exc_info=True)
131         else:
132             imported_module.patch()
133 
134     return on_import
135 
136 
137 def patch_all(**patch_modules):
138     # type: (Dict[str, bool]) -> None
139     """Automatically patches all available modules.
140 
141     In addition to ``patch_modules``, an override can be specified via an
142     environment variable, ``DD_TRACE_<module>_ENABLED`` for each module.
143 
144     ``patch_modules`` have the highest precedence for overriding.
145 
146     :param dict patch_modules: Override whether particular modules are patched or not.
147 
148         >>> patch_all(redis=False, cassandra=False)
149     """
150     modules = PATCH_MODULES.copy()
151 
152     # The enabled setting can be overridden by environment variables
153     for module, enabled in modules.items():
154         env_var = "DD_TRACE_%s_ENABLED" % module.upper()
155         if env_var not in os.environ:
156             continue
157 
158         override_enabled = formats.asbool(os.environ[env_var])
159         modules[module] = override_enabled
160 
161     # Arguments take precedence over the environment and the defaults.
162     modules.update(patch_modules)
163 
164     patch(raise_errors=False, **modules)
165 
166 
167 def patch(raise_errors=True, **patch_modules):
168     # type: (bool, Dict[str, bool]) -> None
169     """Patch only a set of given modules.
170 
171     :param bool raise_errors: Raise error if one patch fail.
172     :param dict patch_modules: List of modules to patch.
173 
174         >>> patch(psycopg=True, elasticsearch=True)
175     """
176     modules = [m for (m, should_patch) in patch_modules.items() if should_patch]
177     for module in modules:
178         if module in _PATCH_ON_IMPORT:
179             modules_to_poi = _PATCH_ON_IMPORT[module]
180             for m in modules_to_poi:
181                 # If the module has already been imported then patch immediately
182                 if m in sys.modules:
183                     _patch_module(module, raise_errors=raise_errors)
184                     break
185                 # Otherwise, add a hook to patch when it is imported for the first time
186                 else:
187                     # Use factory to create handler to close over `module` and `raise_errors` values from this loop
188                     when_imported(m)(_on_import_factory(module, raise_errors))
189 
190             # manually add module to patched modules
191             with _LOCK:
192                 _PATCHED_MODULES.add(module)
193         else:
194             _patch_module(module, raise_errors=raise_errors)
195 
196     patched_modules = _get_patched_modules()
197     log.info(
198         "patched %s/%s modules (%s)",
199         len(patched_modules),
200         len(modules),
201         ",".join(patched_modules),
202     )
203 
204 
205 @deprecated(
206     message="This function will be removed.",
207     version="1.0.0",
208 )
209 def patch_module(module, raise_errors=True):
210     # type: (str, bool) -> bool
211     return _patch_module(module, raise_errors=raise_errors)
212 
213 
214 def _patch_module(module, raise_errors=True):
215     # type: (str, bool) -> bool
216     """Patch a single module
217 
218     Returns if the module got properly patched.
219     """
220     try:
221         return _attempt_patch_module(module)
222     except ModuleNotFoundException:
223         if raise_errors:
224             raise
225         return False
226     except Exception:
227         if raise_errors:
228             raise
229         log.debug("failed to patch %s", module, exc_info=True)
230         return False
231 
232 
233 @deprecated(
234     message="This function will be removed.",
235     version="1.0.0",
236 )
237 def get_patched_modules():
238     # type: () -> List[str]
239     return _get_patched_modules()
240 
241 
242 def _get_patched_modules():
243     # type: () -> List[str]
244     """Get the list of patched modules"""
245     with _LOCK:
246         return sorted(_PATCHED_MODULES)
247 
248 
249 def _attempt_patch_module(module):
250     # type: (str) -> bool
251     """_patch_module will attempt to monkey patch the module.
252 
253     Returns if the module got patched.
254     Can also raise errors if it fails.
255     """
256     path = "ddtrace.contrib.%s" % module
257     with _LOCK:
258         if module in _PATCHED_MODULES and module not in _PATCH_ON_IMPORT:
259             log.debug("already patched: %s", path)
260             return False
261 
262         try:
263             imported_module = importlib.import_module(path)
264         except ImportError:
265             # if the import fails, the integration is not available
266             raise PatchException("integration '%s' not available" % path)
267         else:
268             # if patch() is not available in the module, it means
269             # that the library is not installed in the environment
270             if not hasattr(imported_module, "patch"):
271                 raise ModuleNotFoundException("module '%s' not installed" % module)
272 
273             imported_module.patch()  # type: ignore
274             _PATCHED_MODULES.add(module)
275             return True
276
```
--- 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/ddtrace/monkey.py b/ddtrace/monkey.py
--- a/ddtrace/monkey.py
+++ b/ddtrace/monkey.py
@@ -12,7 +12,6 @@
 import threading
 from typing import Any
 from typing import Callable
-from typing import Dict
 from typing import List
 
 from ddtrace.vendor.wrapt.importer import when_imported
@@ -135,7 +134,7 @@
 
 
 def patch_all(**patch_modules):
-    # type: (Dict[str, bool]) -> None
+    # type: (bool) -> None
     """Automatically patches all available modules.
 
     In addition to ``patch_modules``, an override can be specified via an
@@ -165,7 +164,7 @@
 
 
 def patch(raise_errors=True, **patch_modules):
-    # type: (bool, Dict[str, bool]) -> None
+    # type: (bool, bool) -> None
     """Patch only a set of given modules.
 
     :param bool raise_errors: Raise error if one patch fail.

{"golden_diff": "diff --git a/ddtrace/monkey.py b/ddtrace/monkey.py\n--- a/ddtrace/monkey.py\n+++ b/ddtrace/monkey.py\n@@ -12,7 +12,6 @@\n import threading\n from typing import Any\n from typing import Callable\n-from typing import Dict\n from typing import List\n \n from ddtrace.vendor.wrapt.importer import when_imported\n@@ -135,7 +134,7 @@\n \n \n def patch_all(**patch_modules):\n-    # type: (Dict[str, bool]) -> None\n+    # type: (bool) -> None\n     \"\"\"Automatically patches all available modules.\n \n     In addition to ``patch_modules``, an override can be specified via an\n@@ -165,7 +164,7 @@\n \n \n def patch(raise_errors=True, **patch_modules):\n-    # type: (bool, Dict[str, bool]) -> None\n+    # type: (bool, bool) -> None\n     \"\"\"Patch only a set of given modules.\n \n     :param bool raise_errors: Raise error if one patch fail.\n", "issue": "Incorrect types for patch() and patch_all() keyword arguments\n### Which version of dd-trace-py are you using?\r\n0.51.1\r\n\r\n### Which version of pip are you using?\r\n\r\n20.2.3\r\n\r\n### Which version of the libraries are you using?\r\n\r\nfastapi==0.63.0\r\n\r\n### How can we reproduce your problem?\r\n\r\nI have this line of code: `    ddtrace.patch(fastapi=True)`\r\n\r\nAnd then in the command line I run `mypy project_dir`\r\n\r\n### What is the result that you get?\r\n\r\n`error: Argument \"fastapi\" to \"patch\" has incompatible type \"bool\"; expected \"Dict[str, bool]\"`\r\n\r\n### What is the result that you expected?\r\n\r\nNo type errors\r\n\r\n\r\nI believe this is because the type of the patch_modules parameter should be just `bool` and not `Dict[str, bool]` because it is a keyword arguments parameter (declared with **) for these two functions. See: https://www.python.org/dev/peps/pep-0484/#arbitrary-argument-lists-and-default-argument-values \n", "before_files": [{"content": "\"\"\"Patch libraries to be automatically instrumented.\n\nIt can monkey patch supported standard libraries and third party modules.\nA patched module will automatically report spans with its default configuration.\n\nA library instrumentation can be configured (for instance, to report as another service)\nusing Pin. For that, check its documentation.\n\"\"\"\nimport importlib\nimport os\nimport sys\nimport threading\nfrom typing import Any\nfrom typing import Callable\nfrom typing import Dict\nfrom typing import List\n\nfrom ddtrace.vendor.wrapt.importer import when_imported\n\nfrom .internal.logger import get_logger\nfrom .settings import _config as config\nfrom .utils import formats\nfrom .utils.deprecation import deprecated\n\n\nlog = get_logger(__name__)\n\n# Default set of modules to automatically patch or not\nPATCH_MODULES = {\n    \"asyncio\": True,\n    \"boto\": True,\n    \"botocore\": True,\n    \"bottle\": False,\n    \"cassandra\": True,\n    \"celery\": True,\n    \"consul\": True,\n    \"django\": True,\n    \"elasticsearch\": True,\n    \"algoliasearch\": True,\n    \"futures\": True,\n    \"grpc\": True,\n    \"mongoengine\": True,\n    \"mysql\": True,\n    \"mysqldb\": True,\n    \"pymysql\": True,\n    \"mariadb\": True,\n    \"psycopg\": True,\n    \"pylibmc\": True,\n    \"pymemcache\": True,\n    \"pymongo\": True,\n    \"redis\": True,\n    \"rediscluster\": True,\n    \"requests\": True,\n    \"sanic\": True,\n    \"sqlalchemy\": False,  # Prefer DB client instrumentation\n    \"sqlite3\": True,\n    \"aiohttp\": True,  # requires asyncio (Python 3.4+)\n    \"aiopg\": True,\n    \"aiobotocore\": False,\n    \"httplib\": False,\n    \"urllib3\": False,\n    \"vertica\": True,\n    \"molten\": True,\n    \"jinja2\": True,\n    \"mako\": True,\n    \"flask\": True,\n    \"kombu\": False,\n    \"starlette\": True,\n    # Ignore some web framework integrations that might be configured explicitly in code\n    \"falcon\": False,\n    \"pylons\": False,\n    \"pyramid\": False,\n    # Auto-enable logging if the environment variable DD_LOGS_INJECTION is true\n    \"logging\": config.logs_injection,\n    \"pynamodb\": True,\n    \"pyodbc\": True,\n    \"fastapi\": True,\n    \"dogpile_cache\": True,\n}\n\n_LOCK = threading.Lock()\n_PATCHED_MODULES = set()\n\n# Modules which are patched on first use\n# DEV: These modules are patched when the user first imports them, rather than\n#      explicitly importing and patching them on application startup `ddtrace.patch_all(module=True)`\n# DEV: This ensures we do not patch a module until it is needed\n# DEV: <contrib name> => <list of module names that trigger a patch>\n_PATCH_ON_IMPORT = {\n    \"aiohttp\": (\"aiohttp\",),\n    \"aiobotocore\": (\"aiobotocore\",),\n    \"celery\": (\"celery\",),\n    \"flask\": (\"flask\",),\n    \"gevent\": (\"gevent\",),\n    \"requests\": (\"requests\",),\n    \"botocore\": (\"botocore\",),\n    \"elasticsearch\": (\n        \"elasticsearch\",\n        \"elasticsearch2\",\n        \"elasticsearch5\",\n        \"elasticsearch6\",\n        \"elasticsearch7\",\n    ),\n    \"pynamodb\": (\"pynamodb\",),\n}\n\n\nclass PatchException(Exception):\n    \"\"\"Wraps regular `Exception` class when patching modules\"\"\"\n\n    pass\n\n\nclass ModuleNotFoundException(PatchException):\n    pass\n\n\ndef _on_import_factory(module, raise_errors=True):\n    # type: (str, bool) -> Callable[[Any], None]\n    \"\"\"Factory to create an import hook for the provided module name\"\"\"\n\n    def on_import(hook):\n        # Import and patch module\n        path = \"ddtrace.contrib.%s\" % module\n        try:\n            imported_module = importlib.import_module(path)\n        except ImportError:\n            if raise_errors:\n                raise\n            log.error(\"failed to import ddtrace module %r when patching on import\", path, exc_info=True)\n        else:\n            imported_module.patch()\n\n    return on_import\n\n\ndef patch_all(**patch_modules):\n    # type: (Dict[str, bool]) -> None\n    \"\"\"Automatically patches all available modules.\n\n    In addition to ``patch_modules``, an override can be specified via an\n    environment variable, ``DD_TRACE_<module>_ENABLED`` for each module.\n\n    ``patch_modules`` have the highest precedence for overriding.\n\n    :param dict patch_modules: Override whether particular modules are patched or not.\n\n        >>> patch_all(redis=False, cassandra=False)\n    \"\"\"\n    modules = PATCH_MODULES.copy()\n\n    # The enabled setting can be overridden by environment variables\n    for module, enabled in modules.items():\n        env_var = \"DD_TRACE_%s_ENABLED\" % module.upper()\n        if env_var not in os.environ:\n            continue\n\n        override_enabled = formats.asbool(os.environ[env_var])\n        modules[module] = override_enabled\n\n    # Arguments take precedence over the environment and the defaults.\n    modules.update(patch_modules)\n\n    patch(raise_errors=False, **modules)\n\n\ndef patch(raise_errors=True, **patch_modules):\n    # type: (bool, Dict[str, bool]) -> None\n    \"\"\"Patch only a set of given modules.\n\n    :param bool raise_errors: Raise error if one patch fail.\n    :param dict patch_modules: List of modules to patch.\n\n        >>> patch(psycopg=True, elasticsearch=True)\n    \"\"\"\n    modules = [m for (m, should_patch) in patch_modules.items() if should_patch]\n    for module in modules:\n        if module in _PATCH_ON_IMPORT:\n            modules_to_poi = _PATCH_ON_IMPORT[module]\n            for m in modules_to_poi:\n                # If the module has already been imported then patch immediately\n                if m in sys.modules:\n                    _patch_module(module, raise_errors=raise_errors)\n                    break\n                # Otherwise, add a hook to patch when it is imported for the first time\n                else:\n                    # Use factory to create handler to close over `module` and `raise_errors` values from this loop\n                    when_imported(m)(_on_import_factory(module, raise_errors))\n\n            # manually add module to patched modules\n            with _LOCK:\n                _PATCHED_MODULES.add(module)\n        else:\n            _patch_module(module, raise_errors=raise_errors)\n\n    patched_modules = _get_patched_modules()\n    log.info(\n        \"patched %s/%s modules (%s)\",\n        len(patched_modules),\n        len(modules),\n        \",\".join(patched_modules),\n    )\n\n\n@deprecated(\n    message=\"This function will be removed.\",\n    version=\"1.0.0\",\n)\ndef patch_module(module, raise_errors=True):\n    # type: (str, bool) -> bool\n    return _patch_module(module, raise_errors=raise_errors)\n\n\ndef _patch_module(module, raise_errors=True):\n    # type: (str, bool) -> bool\n    \"\"\"Patch a single module\n\n    Returns if the module got properly patched.\n    \"\"\"\n    try:\n        return _attempt_patch_module(module)\n    except ModuleNotFoundException:\n        if raise_errors:\n            raise\n        return False\n    except Exception:\n        if raise_errors:\n            raise\n        log.debug(\"failed to patch %s\", module, exc_info=True)\n        return False\n\n\n@deprecated(\n    message=\"This function will be removed.\",\n    version=\"1.0.0\",\n)\ndef get_patched_modules():\n    # type: () -> List[str]\n    return _get_patched_modules()\n\n\ndef _get_patched_modules():\n    # type: () -> List[str]\n    \"\"\"Get the list of patched modules\"\"\"\n    with _LOCK:\n        return sorted(_PATCHED_MODULES)\n\n\ndef _attempt_patch_module(module):\n    # type: (str) -> bool\n    \"\"\"_patch_module will attempt to monkey patch the module.\n\n    Returns if the module got patched.\n    Can also raise errors if it fails.\n    \"\"\"\n    path = \"ddtrace.contrib.%s\" % module\n    with _LOCK:\n        if module in _PATCHED_MODULES and module not in _PATCH_ON_IMPORT:\n            log.debug(\"already patched: %s\", path)\n            return False\n\n        try:\n            imported_module = importlib.import_module(path)\n        except ImportError:\n            # if the import fails, the integration is not available\n            raise PatchException(\"integration '%s' not available\" % path)\n        else:\n            # if patch() is not available in the module, it means\n            # that the library is not installed in the environment\n            if not hasattr(imported_module, \"patch\"):\n                raise ModuleNotFoundException(\"module '%s' not installed\" % module)\n\n            imported_module.patch()  # type: ignore\n            _PATCHED_MODULES.add(module)\n            return True\n", "path": "ddtrace/monkey.py"}], "after_files": [{"content": "\"\"\"Patch libraries to be automatically instrumented.\n\nIt can monkey patch supported standard libraries and third party modules.\nA patched module will automatically report spans with its default configuration.\n\nA library instrumentation can be configured (for instance, to report as another service)\nusing Pin. For that, check its documentation.\n\"\"\"\nimport importlib\nimport os\nimport sys\nimport threading\nfrom typing import Any\nfrom typing import Callable\nfrom typing import List\n\nfrom ddtrace.vendor.wrapt.importer import when_imported\n\nfrom .internal.logger import get_logger\nfrom .settings import _config as config\nfrom .utils import formats\nfrom .utils.deprecation import deprecated\n\n\nlog = get_logger(__name__)\n\n# Default set of modules to automatically patch or not\nPATCH_MODULES = {\n    \"asyncio\": True,\n    \"boto\": True,\n    \"botocore\": True,\n    \"bottle\": False,\n    \"cassandra\": True,\n    \"celery\": True,\n    \"consul\": True,\n    \"django\": True,\n    \"elasticsearch\": True,\n    \"algoliasearch\": True,\n    \"futures\": True,\n    \"grpc\": True,\n    \"mongoengine\": True,\n    \"mysql\": True,\n    \"mysqldb\": True,\n    \"pymysql\": True,\n    \"mariadb\": True,\n    \"psycopg\": True,\n    \"pylibmc\": True,\n    \"pymemcache\": True,\n    \"pymongo\": True,\n    \"redis\": True,\n    \"rediscluster\": True,\n    \"requests\": True,\n    \"sanic\": True,\n    \"sqlalchemy\": False,  # Prefer DB client instrumentation\n    \"sqlite3\": True,\n    \"aiohttp\": True,  # requires asyncio (Python 3.4+)\n    \"aiopg\": True,\n    \"aiobotocore\": False,\n    \"httplib\": False,\n    \"urllib3\": False,\n    \"vertica\": True,\n    \"molten\": True,\n    \"jinja2\": True,\n    \"mako\": True,\n    \"flask\": True,\n    \"kombu\": False,\n    \"starlette\": True,\n    # Ignore some web framework integrations that might be configured explicitly in code\n    \"falcon\": False,\n    \"pylons\": False,\n    \"pyramid\": False,\n    # Auto-enable logging if the environment variable DD_LOGS_INJECTION is true\n    \"logging\": config.logs_injection,\n    \"pynamodb\": True,\n    \"pyodbc\": True,\n    \"fastapi\": True,\n    \"dogpile_cache\": True,\n}\n\n_LOCK = threading.Lock()\n_PATCHED_MODULES = set()\n\n# Modules which are patched on first use\n# DEV: These modules are patched when the user first imports them, rather than\n#      explicitly importing and patching them on application startup `ddtrace.patch_all(module=True)`\n# DEV: This ensures we do not patch a module until it is needed\n# DEV: <contrib name> => <list of module names that trigger a patch>\n_PATCH_ON_IMPORT = {\n    \"aiohttp\": (\"aiohttp\",),\n    \"aiobotocore\": (\"aiobotocore\",),\n    \"celery\": (\"celery\",),\n    \"flask\": (\"flask\",),\n    \"gevent\": (\"gevent\",),\n    \"requests\": (\"requests\",),\n    \"botocore\": (\"botocore\",),\n    \"elasticsearch\": (\n        \"elasticsearch\",\n        \"elasticsearch2\",\n        \"elasticsearch5\",\n        \"elasticsearch6\",\n        \"elasticsearch7\",\n    ),\n    \"pynamodb\": (\"pynamodb\",),\n}\n\n\nclass PatchException(Exception):\n    \"\"\"Wraps regular `Exception` class when patching modules\"\"\"\n\n    pass\n\n\nclass ModuleNotFoundException(PatchException):\n    pass\n\n\ndef _on_import_factory(module, raise_errors=True):\n    # type: (str, bool) -> Callable[[Any], None]\n    \"\"\"Factory to create an import hook for the provided module name\"\"\"\n\n    def on_import(hook):\n        # Import and patch module\n        path = \"ddtrace.contrib.%s\" % module\n        try:\n            imported_module = importlib.import_module(path)\n        except ImportError:\n            if raise_errors:\n                raise\n            log.error(\"failed to import ddtrace module %r when patching on import\", path, exc_info=True)\n        else:\n            imported_module.patch()\n\n    return on_import\n\n\ndef patch_all(**patch_modules):\n    # type: (bool) -> None\n    \"\"\"Automatically patches all available modules.\n\n    In addition to ``patch_modules``, an override can be specified via an\n    environment variable, ``DD_TRACE_<module>_ENABLED`` for each module.\n\n    ``patch_modules`` have the highest precedence for overriding.\n\n    :param dict patch_modules: Override whether particular modules are patched or not.\n\n        >>> patch_all(redis=False, cassandra=False)\n    \"\"\"\n    modules = PATCH_MODULES.copy()\n\n    # The enabled setting can be overridden by environment variables\n    for module, enabled in modules.items():\n        env_var = \"DD_TRACE_%s_ENABLED\" % module.upper()\n        if env_var not in os.environ:\n            continue\n\n        override_enabled = formats.asbool(os.environ[env_var])\n        modules[module] = override_enabled\n\n    # Arguments take precedence over the environment and the defaults.\n    modules.update(patch_modules)\n\n    patch(raise_errors=False, **modules)\n\n\ndef patch(raise_errors=True, **patch_modules):\n    # type: (bool, bool) -> None\n    \"\"\"Patch only a set of given modules.\n\n    :param bool raise_errors: Raise error if one patch fail.\n    :param dict patch_modules: List of modules to patch.\n\n        >>> patch(psycopg=True, elasticsearch=True)\n    \"\"\"\n    modules = [m for (m, should_patch) in patch_modules.items() if should_patch]\n    for module in modules:\n        if module in _PATCH_ON_IMPORT:\n            modules_to_poi = _PATCH_ON_IMPORT[module]\n            for m in modules_to_poi:\n                # If the module has already been imported then patch immediately\n                if m in sys.modules:\n                    _patch_module(module, raise_errors=raise_errors)\n                    break\n                # Otherwise, add a hook to patch when it is imported for the first time\n                else:\n                    # Use factory to create handler to close over `module` and `raise_errors` values from this loop\n                    when_imported(m)(_on_import_factory(module, raise_errors))\n\n            # manually add module to patched modules\n            with _LOCK:\n                _PATCHED_MODULES.add(module)\n        else:\n            _patch_module(module, raise_errors=raise_errors)\n\n    patched_modules = _get_patched_modules()\n    log.info(\n        \"patched %s/%s modules (%s)\",\n        len(patched_modules),\n        len(modules),\n        \",\".join(patched_modules),\n    )\n\n\n@deprecated(\n    message=\"This function will be removed.\",\n    version=\"1.0.0\",\n)\ndef patch_module(module, raise_errors=True):\n    # type: (str, bool) -> bool\n    return _patch_module(module, raise_errors=raise_errors)\n\n\ndef _patch_module(module, raise_errors=True):\n    # type: (str, bool) -> bool\n    \"\"\"Patch a single module\n\n    Returns if the module got properly patched.\n    \"\"\"\n    try:\n        return _attempt_patch_module(module)\n    except ModuleNotFoundException:\n        if raise_errors:\n            raise\n        return False\n    except Exception:\n        if raise_errors:\n            raise\n        log.debug(\"failed to patch %s\", module, exc_info=True)\n        return False\n\n\n@deprecated(\n    message=\"This function will be removed.\",\n    version=\"1.0.0\",\n)\ndef get_patched_modules():\n    # type: () -> List[str]\n    return _get_patched_modules()\n\n\ndef _get_patched_modules():\n    # type: () -> List[str]\n    \"\"\"Get the list of patched modules\"\"\"\n    with _LOCK:\n        return sorted(_PATCHED_MODULES)\n\n\ndef _attempt_patch_module(module):\n    # type: (str) -> bool\n    \"\"\"_patch_module will attempt to monkey patch the module.\n\n    Returns if the module got patched.\n    Can also raise errors if it fails.\n    \"\"\"\n    path = \"ddtrace.contrib.%s\" % module\n    with _LOCK:\n        if module in _PATCHED_MODULES and module not in _PATCH_ON_IMPORT:\n            log.debug(\"already patched: %s\", path)\n            return False\n\n        try:\n            imported_module = importlib.import_module(path)\n        except ImportError:\n            # if the import fails, the integration is not available\n            raise PatchException(\"integration '%s' not available\" % path)\n        else:\n            # if patch() is not available in the module, it means\n            # that the library is not installed in the environment\n            if not hasattr(imported_module, \"patch\"):\n                raise ModuleNotFoundException(\"module '%s' not installed\" % module)\n\n            imported_module.patch()  # type: ignore\n            _PATCHED_MODULES.add(module)\n            return True\n", "path": "ddtrace/monkey.py"}]}