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