cavisson-pythonagent 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. cavisson_pythonagent-0.0.1.dist-info/METADATA +32 -0
  2. cavisson_pythonagent-0.0.1.dist-info/RECORD +180 -0
  3. cavisson_pythonagent-0.0.1.dist-info/WHEEL +5 -0
  4. cavisson_pythonagent-0.0.1.dist-info/licenses/LICENSE +19 -0
  5. cavisson_pythonagent-0.0.1.dist-info/top_level.txt +1 -0
  6. pythonagent/__init__.py +22 -0
  7. pythonagent/agent/__init__.py +219 -0
  8. pythonagent/agent/internal/__init__.py +1 -0
  9. pythonagent/agent/internal/agent.py +1651 -0
  10. pythonagent/agent/internal/framesinfo.py +152 -0
  11. pythonagent/agent/internal/heap_dump.py +39 -0
  12. pythonagent/agent/internal/intercept_module.py +70 -0
  13. pythonagent/agent/internal/logs.py +122 -0
  14. pythonagent/agent/internal/metadata/__init__.py +0 -0
  15. pythonagent/agent/internal/metadata/agent_meta_data.py +276 -0
  16. pythonagent/agent/internal/proc_compat.py +75 -0
  17. pythonagent/agent/internal/profile.py +47 -0
  18. pythonagent/agent/internal/provider.py +83 -0
  19. pythonagent/agent/internal/thread_dump.py +85 -0
  20. pythonagent/agent/internal/udp.py +245 -0
  21. pythonagent/agent/internal/udp_message.py +800 -0
  22. pythonagent/agent/probes/Instrumentation/__init__.py +340 -0
  23. pythonagent/agent/probes/Instrumentation/find.py +243 -0
  24. pythonagent/agent/probes/Instrumentation/module_version_resolver.py +155 -0
  25. pythonagent/agent/probes/Instrumentation/new_parser.py +64 -0
  26. pythonagent/agent/probes/Instrumentation/parser.py +129 -0
  27. pythonagent/agent/probes/__init__.py +219 -0
  28. pythonagent/agent/probes/base.py +303 -0
  29. pythonagent/agent/probes/cache/__init__.py +51 -0
  30. pythonagent/agent/probes/cache/redis.py +119 -0
  31. pythonagent/agent/probes/cache/redis_asyncio.py +83 -0
  32. pythonagent/agent/probes/coroutines/__init__.py +1 -0
  33. pythonagent/agent/probes/coroutines/asyncio.py +63 -0
  34. pythonagent/agent/probes/elasticdb/__init__.py +7 -0
  35. pythonagent/agent/probes/elasticdb/aelastic.py +54 -0
  36. pythonagent/agent/probes/frameworks/__init__.py +27 -0
  37. pythonagent/agent/probes/frameworks/agentprofiler.py +105 -0
  38. pythonagent/agent/probes/frameworks/aiohttp_web.py +155 -0
  39. pythonagent/agent/probes/frameworks/aisess.py +151 -0
  40. pythonagent/agent/probes/frameworks/asgi.py +340 -0
  41. pythonagent/agent/probes/frameworks/bottle.py +27 -0
  42. pythonagent/agent/probes/frameworks/cherry.py +25 -0
  43. pythonagent/agent/probes/frameworks/django.py +128 -0
  44. pythonagent/agent/probes/frameworks/falcon.py +21 -0
  45. pythonagent/agent/probes/frameworks/fastapi.py +35 -0
  46. pythonagent/agent/probes/frameworks/flask.py +30 -0
  47. pythonagent/agent/probes/frameworks/pyramid.py +56 -0
  48. pythonagent/agent/probes/frameworks/test.py +108 -0
  49. pythonagent/agent/probes/frameworks/tornado_async_web.py +117 -0
  50. pythonagent/agent/probes/frameworks/tornado_web.py +133 -0
  51. pythonagent/agent/probes/frameworks/wsgi.py +353 -0
  52. pythonagent/agent/probes/grpc/__init__.py +76 -0
  53. pythonagent/agent/probes/grpc/client_interceptor.py +132 -0
  54. pythonagent/agent/probes/grpc/server_interceptor.py +129 -0
  55. pythonagent/agent/probes/havoc/__init__.py +0 -0
  56. pythonagent/agent/probes/havoc/custom_memory_stress.py +186 -0
  57. pythonagent/agent/probes/havoc/custom_thread_stress.py +187 -0
  58. pythonagent/agent/probes/havoc/havoc_constants.py +218 -0
  59. pythonagent/agent/probes/havoc/havoc_manager.py +981 -0
  60. pythonagent/agent/probes/http/__init__.py +49 -0
  61. pythonagent/agent/probes/http/aiohttp_client.py +59 -0
  62. pythonagent/agent/probes/http/boto.py +12 -0
  63. pythonagent/agent/probes/http/httplib.py +110 -0
  64. pythonagent/agent/probes/http/httpx_client.py +116 -0
  65. pythonagent/agent/probes/http/requests.py +15 -0
  66. pythonagent/agent/probes/http/tornado_httpclient.py +85 -0
  67. pythonagent/agent/probes/http/urllib3.py +16 -0
  68. pythonagent/agent/probes/langchain/__init__.py +21 -0
  69. pythonagent/agent/probes/langchain/base_tool.py +95 -0
  70. pythonagent/agent/probes/langchain/langchain_community.py +136 -0
  71. pythonagent/agent/probes/langchain/langchain_core.py +32 -0
  72. pythonagent/agent/probes/langchain/langchain_openai.py +110 -0
  73. pythonagent/agent/probes/logging/__init__.py +106 -0
  74. pythonagent/agent/probes/message_brokers/__init__.py +4 -0
  75. pythonagent/agent/probes/message_brokers/pika.py +126 -0
  76. pythonagent/agent/probes/mongodb/__init__.py +6 -0
  77. pythonagent/agent/probes/mongodb/pymongo.py +286 -0
  78. pythonagent/agent/probes/openai/__init__.py +3 -0
  79. pythonagent/agent/probes/openai/openai.py +797 -0
  80. pythonagent/agent/probes/span.py +101 -0
  81. pythonagent/agent/probes/sql/__init__.py +13 -0
  82. pythonagent/agent/probes/sql/botocores3.py +51 -0
  83. pythonagent/agent/probes/sql/dbapi.py +285 -0
  84. pythonagent/agent/probes/sql/dynamodb.py +90 -0
  85. pythonagent/agent/probes/sql/mysql_connector.py +24 -0
  86. pythonagent/agent/probes/sql/mysql_connector_cext.py +24 -0
  87. pythonagent/agent/probes/sql/mysqldb.py +43 -0
  88. pythonagent/agent/probes/sql/psycopg2.py +174 -0
  89. pythonagent/agent/probes/sql/pymysql.py +25 -0
  90. pythonagent/bootstrap/__init__.py +0 -0
  91. pythonagent/bootstrap/cav_gunicorn.py +26 -0
  92. pythonagent/bootstrap/cavagent_lambda_wrapper.py +291 -0
  93. pythonagent/bootstrap/run.py +47 -0
  94. pythonagent/bootstrap/sitecustomize.py +287 -0
  95. pythonagent/cavisson/netdiagnostics/CavAgent/instrumentationprofile.json +26 -0
  96. pythonagent/cavisson/netdiagnostics/CavAgent/interceptor_points.txt +29 -0
  97. pythonagent/cavisson/netdiagnostics/python/CavAgent/instrumentationprofile.json +42 -0
  98. pythonagent/cavisson/netdiagnostics/python/CavAgent/interceptor_points.txt +29 -0
  99. pythonagent/cavisson/netdiagnostics/python/config/ndsettings.conf +6 -0
  100. pythonagent/config.py +279 -0
  101. pythonagent/find.py +72 -0
  102. pythonagent/find_mod_cls_name.py +54 -0
  103. pythonagent/lang.py +131 -0
  104. pythonagent/lib.py +91 -0
  105. pythonagent/main/__init__.py +0 -0
  106. pythonagent/main/pytrace/__init__.py +79 -0
  107. pythonagent/main/pytrace/commands/__init__.py +0 -0
  108. pythonagent/main/pytrace/commands/auto_discovery.py +25 -0
  109. pythonagent/main/pytrace/commands/run.py +401 -0
  110. pythonagent/main/pytrace/pytrace.py +133 -0
  111. pythonagent/main/wsgi.py +6 -0
  112. pythonagent/main.py +27 -0
  113. pythonagent/run.py +46 -0
  114. pythonagent/sqins.py +8 -0
  115. pythonagent/test.py +73 -0
  116. pythonagent/utils.py +168 -0
  117. pythonagent/vendor/__init__.py +0 -0
  118. pythonagent/vendor/pympler/__init__.py +1 -0
  119. pythonagent/vendor/pympler/asizeof.py +2810 -0
  120. pythonagent/vendor/pympler/charts.py +62 -0
  121. pythonagent/vendor/pympler/classtracker.py +590 -0
  122. pythonagent/vendor/pympler/classtracker_stats.py +780 -0
  123. pythonagent/vendor/pympler/garbagegraph.py +80 -0
  124. pythonagent/vendor/pympler/mprofile.py +97 -0
  125. pythonagent/vendor/pympler/muppy.py +275 -0
  126. pythonagent/vendor/pympler/panels.py +115 -0
  127. pythonagent/vendor/pympler/process.py +238 -0
  128. pythonagent/vendor/pympler/py.typed +0 -0
  129. pythonagent/vendor/pympler/refbrowser.py +451 -0
  130. pythonagent/vendor/pympler/refgraph.py +350 -0
  131. pythonagent/vendor/pympler/summary.py +321 -0
  132. pythonagent/vendor/pympler/tracker.py +267 -0
  133. pythonagent/vendor/pympler/util/__init__.py +0 -0
  134. pythonagent/vendor/pympler/util/bottle.py +3809 -0
  135. pythonagent/vendor/pympler/util/compat.py +23 -0
  136. pythonagent/vendor/pympler/util/stringutils.py +77 -0
  137. pythonagent/vendor/pympler/web.py +346 -0
  138. pythonagent/vendor/werkzeug/__init__.py +20 -0
  139. pythonagent/vendor/werkzeug/_compat.py +228 -0
  140. pythonagent/vendor/werkzeug/_internal.py +473 -0
  141. pythonagent/vendor/werkzeug/_reloader.py +341 -0
  142. pythonagent/vendor/werkzeug/datastructures.py +3120 -0
  143. pythonagent/vendor/werkzeug/debug/__init__.py +498 -0
  144. pythonagent/vendor/werkzeug/debug/console.py +218 -0
  145. pythonagent/vendor/werkzeug/debug/repr.py +297 -0
  146. pythonagent/vendor/werkzeug/debug/tbtools.py +628 -0
  147. pythonagent/vendor/werkzeug/exceptions.py +829 -0
  148. pythonagent/vendor/werkzeug/filesystem.py +64 -0
  149. pythonagent/vendor/werkzeug/formparser.py +584 -0
  150. pythonagent/vendor/werkzeug/http.py +1307 -0
  151. pythonagent/vendor/werkzeug/local.py +420 -0
  152. pythonagent/vendor/werkzeug/middleware/__init__.py +25 -0
  153. pythonagent/vendor/werkzeug/middleware/dispatcher.py +66 -0
  154. pythonagent/vendor/werkzeug/middleware/http_proxy.py +219 -0
  155. pythonagent/vendor/werkzeug/middleware/lint.py +408 -0
  156. pythonagent/vendor/werkzeug/middleware/profiler.py +132 -0
  157. pythonagent/vendor/werkzeug/middleware/proxy_fix.py +169 -0
  158. pythonagent/vendor/werkzeug/middleware/shared_data.py +293 -0
  159. pythonagent/vendor/werkzeug/posixemulation.py +117 -0
  160. pythonagent/vendor/werkzeug/routing.py +2210 -0
  161. pythonagent/vendor/werkzeug/security.py +249 -0
  162. pythonagent/vendor/werkzeug/serving.py +1117 -0
  163. pythonagent/vendor/werkzeug/test.py +1123 -0
  164. pythonagent/vendor/werkzeug/testapp.py +241 -0
  165. pythonagent/vendor/werkzeug/urls.py +1138 -0
  166. pythonagent/vendor/werkzeug/useragents.py +202 -0
  167. pythonagent/vendor/werkzeug/utils.py +778 -0
  168. pythonagent/vendor/werkzeug/wrappers/__init__.py +36 -0
  169. pythonagent/vendor/werkzeug/wrappers/accept.py +50 -0
  170. pythonagent/vendor/werkzeug/wrappers/auth.py +33 -0
  171. pythonagent/vendor/werkzeug/wrappers/base_request.py +673 -0
  172. pythonagent/vendor/werkzeug/wrappers/base_response.py +700 -0
  173. pythonagent/vendor/werkzeug/wrappers/common_descriptors.py +341 -0
  174. pythonagent/vendor/werkzeug/wrappers/cors.py +100 -0
  175. pythonagent/vendor/werkzeug/wrappers/etag.py +304 -0
  176. pythonagent/vendor/werkzeug/wrappers/json.py +145 -0
  177. pythonagent/vendor/werkzeug/wrappers/request.py +49 -0
  178. pythonagent/vendor/werkzeug/wrappers/response.py +84 -0
  179. pythonagent/vendor/werkzeug/wrappers/user_agent.py +14 -0
  180. pythonagent/vendor/werkzeug/wsgi.py +1000 -0
@@ -0,0 +1,341 @@
1
+ import os
2
+ import subprocess
3
+ import sys
4
+ import threading
5
+ import time
6
+ from itertools import chain
7
+
8
+ from ._compat import iteritems
9
+ from ._compat import PY2
10
+ from ._compat import text_type
11
+ from ._internal import _log
12
+
13
+
14
+ def _iter_module_files():
15
+ """This iterates over all relevant Python files. It goes through all
16
+ loaded files from modules, all files in folders of already loaded modules
17
+ as well as all files reachable through a package.
18
+ """
19
+ # The list call is necessary on Python 3 in case the module
20
+ # dictionary modifies during iteration.
21
+ for module in list(sys.modules.values()):
22
+ if module is None:
23
+ continue
24
+ filename = getattr(module, "__file__", None)
25
+ if filename:
26
+ if os.path.isdir(filename) and os.path.exists(
27
+ os.path.join(filename, "__init__.py")
28
+ ):
29
+ filename = os.path.join(filename, "__init__.py")
30
+
31
+ old = None
32
+ while not os.path.isfile(filename):
33
+ old = filename
34
+ filename = os.path.dirname(filename)
35
+ if filename == old:
36
+ break
37
+ else:
38
+ if filename[-4:] in (".pyc", ".pyo"):
39
+ filename = filename[:-1]
40
+ yield filename
41
+
42
+
43
+ def _find_observable_paths(extra_files=None):
44
+ """Finds all paths that should be observed."""
45
+ rv = set(
46
+ os.path.dirname(os.path.abspath(x)) if os.path.isfile(x) else os.path.abspath(x)
47
+ for x in sys.path
48
+ )
49
+
50
+ for filename in extra_files or ():
51
+ rv.add(os.path.dirname(os.path.abspath(filename)))
52
+
53
+ for module in list(sys.modules.values()):
54
+ fn = getattr(module, "__file__", None)
55
+ if fn is None:
56
+ continue
57
+ fn = os.path.abspath(fn)
58
+ rv.add(os.path.dirname(fn))
59
+
60
+ return _find_common_roots(rv)
61
+
62
+
63
+ def _get_args_for_reloading():
64
+ """Determine how the script was executed, and return the args needed
65
+ to execute it again in a new process.
66
+ """
67
+ rv = [sys.executable]
68
+ py_script = sys.argv[0]
69
+ args = sys.argv[1:]
70
+ # Need to look at main module to determine how it was executed.
71
+ __main__ = sys.modules["__main__"]
72
+
73
+ # The value of __package__ indicates how Python was called. It may
74
+ # not exist if a setuptools script is installed as an egg. It may be
75
+ # set incorrectly for entry points created with pip on Windows.
76
+ if getattr(__main__, "__package__", None) is None or (
77
+ os.name == "nt"
78
+ and __main__.__package__ == ""
79
+ and not os.path.exists(py_script)
80
+ and os.path.exists(py_script + ".exe")
81
+ ):
82
+ # Executed a file, like "python app.py".
83
+ py_script = os.path.abspath(py_script)
84
+
85
+ if os.name == "nt":
86
+ # Windows entry points have ".exe" extension and should be
87
+ # called directly.
88
+ if not os.path.exists(py_script) and os.path.exists(py_script + ".exe"):
89
+ py_script += ".exe"
90
+
91
+ if (
92
+ os.path.splitext(sys.executable)[1] == ".exe"
93
+ and os.path.splitext(py_script)[1] == ".exe"
94
+ ):
95
+ rv.pop(0)
96
+
97
+ rv.append(py_script)
98
+ else:
99
+ # Executed a module, like "python -m werkzeug.serving".
100
+ if sys.argv[0] == "-m":
101
+ # Flask works around previous behavior by putting
102
+ # "-m flask" in sys.argv.
103
+ # TODO remove this once Flask no longer misbehaves
104
+ args = sys.argv
105
+ else:
106
+ if os.path.isfile(py_script):
107
+ # Rewritten by Python from "-m script" to "/path/to/script.py".
108
+ py_module = __main__.__package__
109
+ name = os.path.splitext(os.path.basename(py_script))[0]
110
+
111
+ if name != "__main__":
112
+ py_module += "." + name
113
+ else:
114
+ # Incorrectly rewritten by pydevd debugger from "-m script" to "script".
115
+ py_module = py_script
116
+
117
+ rv.extend(("-m", py_module.lstrip(".")))
118
+
119
+ rv.extend(args)
120
+ return rv
121
+
122
+
123
+ def _find_common_roots(paths):
124
+ """Out of some paths it finds the common roots that need monitoring."""
125
+ paths = [x.split(os.path.sep) for x in paths]
126
+ root = {}
127
+ for chunks in sorted(paths, key=len, reverse=True):
128
+ node = root
129
+ for chunk in chunks:
130
+ node = node.setdefault(chunk, {})
131
+ node.clear()
132
+
133
+ rv = set()
134
+
135
+ def _walk(node, path):
136
+ for prefix, child in iteritems(node):
137
+ _walk(child, path + (prefix,))
138
+ if not node:
139
+ rv.add("/".join(path))
140
+
141
+ _walk(root, ())
142
+ return rv
143
+
144
+
145
+ class ReloaderLoop(object):
146
+ name = None
147
+
148
+ # monkeypatched by testsuite. wrapping with `staticmethod` is required in
149
+ # case time.sleep has been replaced by a non-c function (e.g. by
150
+ # `eventlet.monkey_patch`) before we get here
151
+ _sleep = staticmethod(time.sleep)
152
+
153
+ def __init__(self, extra_files=None, interval=1):
154
+ self.extra_files = set(os.path.abspath(x) for x in extra_files or ())
155
+ self.interval = interval
156
+
157
+ def run(self):
158
+ pass
159
+
160
+ def restart_with_reloader(self):
161
+ """Spawn a new Python interpreter with the same arguments as this one,
162
+ but running the reloader thread.
163
+ """
164
+ while 1:
165
+ _log("info", " * Restarting with %s" % self.name)
166
+ args = _get_args_for_reloading()
167
+
168
+ # a weird bug on windows. sometimes unicode strings end up in the
169
+ # environment and subprocess.call does not like this, encode them
170
+ # to latin1 and continue.
171
+ if os.name == "nt" and PY2:
172
+ new_environ = {}
173
+ for key, value in iteritems(os.environ):
174
+ if isinstance(key, text_type):
175
+ key = key.encode("iso-8859-1")
176
+ if isinstance(value, text_type):
177
+ value = value.encode("iso-8859-1")
178
+ new_environ[key] = value
179
+ else:
180
+ new_environ = os.environ.copy()
181
+
182
+ new_environ["WERKZEUG_RUN_MAIN"] = "true"
183
+ exit_code = subprocess.call(args, env=new_environ, close_fds=False)
184
+ if exit_code != 3:
185
+ return exit_code
186
+
187
+ def trigger_reload(self, filename):
188
+ self.log_reload(filename)
189
+ sys.exit(3)
190
+
191
+ def log_reload(self, filename):
192
+ filename = os.path.abspath(filename)
193
+ _log("info", " * Detected change in %r, reloading" % filename)
194
+
195
+
196
+ class StatReloaderLoop(ReloaderLoop):
197
+ name = "stat"
198
+
199
+ def run(self):
200
+ mtimes = {}
201
+ while 1:
202
+ for filename in chain(_iter_module_files(), self.extra_files):
203
+ try:
204
+ mtime = os.stat(filename).st_mtime
205
+ except OSError:
206
+ continue
207
+
208
+ old_time = mtimes.get(filename)
209
+ if old_time is None:
210
+ mtimes[filename] = mtime
211
+ continue
212
+ elif mtime > old_time:
213
+ self.trigger_reload(filename)
214
+ self._sleep(self.interval)
215
+
216
+
217
+ class WatchdogReloaderLoop(ReloaderLoop):
218
+ def __init__(self, *args, **kwargs):
219
+ ReloaderLoop.__init__(self, *args, **kwargs)
220
+ from watchdog.observers import Observer
221
+ from watchdog.events import FileSystemEventHandler
222
+
223
+ self.observable_paths = set()
224
+
225
+ def _check_modification(filename):
226
+ if filename in self.extra_files:
227
+ self.trigger_reload(filename)
228
+ dirname = os.path.dirname(filename)
229
+ if dirname.startswith(tuple(self.observable_paths)):
230
+ if filename.endswith((".pyc", ".pyo", ".py")):
231
+ self.trigger_reload(filename)
232
+
233
+ class _CustomHandler(FileSystemEventHandler):
234
+ def on_created(self, event):
235
+ _check_modification(event.src_path)
236
+
237
+ def on_modified(self, event):
238
+ _check_modification(event.src_path)
239
+
240
+ def on_moved(self, event):
241
+ _check_modification(event.src_path)
242
+ _check_modification(event.dest_path)
243
+
244
+ def on_deleted(self, event):
245
+ _check_modification(event.src_path)
246
+
247
+ reloader_name = Observer.__name__.lower()
248
+ if reloader_name.endswith("observer"):
249
+ reloader_name = reloader_name[:-8]
250
+ reloader_name += " reloader"
251
+
252
+ self.name = reloader_name
253
+
254
+ self.observer_class = Observer
255
+ self.event_handler = _CustomHandler()
256
+ self.should_reload = False
257
+
258
+ def trigger_reload(self, filename):
259
+ # This is called inside an event handler, which means throwing
260
+ # SystemExit has no effect.
261
+ # https://github.com/gorakhargosh/watchdog/issues/294
262
+ self.should_reload = True
263
+ self.log_reload(filename)
264
+
265
+ def run(self):
266
+ watches = {}
267
+ observer = self.observer_class()
268
+ observer.start()
269
+
270
+ try:
271
+ while not self.should_reload:
272
+ to_delete = set(watches)
273
+ paths = _find_observable_paths(self.extra_files)
274
+ for path in paths:
275
+ if path not in watches:
276
+ try:
277
+ watches[path] = observer.schedule(
278
+ self.event_handler, path, recursive=True
279
+ )
280
+ except OSError:
281
+ # Clear this path from list of watches We don't want
282
+ # the same error message showing again in the next
283
+ # iteration.
284
+ watches[path] = None
285
+ to_delete.discard(path)
286
+ for path in to_delete:
287
+ watch = watches.pop(path, None)
288
+ if watch is not None:
289
+ observer.unschedule(watch)
290
+ self.observable_paths = paths
291
+ self._sleep(self.interval)
292
+ finally:
293
+ observer.stop()
294
+ observer.join()
295
+
296
+ sys.exit(3)
297
+
298
+
299
+ reloader_loops = {"stat": StatReloaderLoop, "watchdog": WatchdogReloaderLoop}
300
+
301
+ try:
302
+ __import__("watchdog.observers")
303
+ except ImportError:
304
+ reloader_loops["auto"] = reloader_loops["stat"]
305
+ else:
306
+ reloader_loops["auto"] = reloader_loops["watchdog"]
307
+
308
+
309
+ def ensure_echo_on():
310
+ """Ensure that echo mode is enabled. Some tools such as PDB disable
311
+ it which causes usability issues after reload."""
312
+ # tcgetattr will fail if stdin isn't a tty
313
+ if not sys.stdin.isatty():
314
+ return
315
+ try:
316
+ import termios
317
+ except ImportError:
318
+ return
319
+ attributes = termios.tcgetattr(sys.stdin)
320
+ if not attributes[3] & termios.ECHO:
321
+ attributes[3] |= termios.ECHO
322
+ termios.tcsetattr(sys.stdin, termios.TCSANOW, attributes)
323
+
324
+
325
+ def run_with_reloader(main_func, extra_files=None, interval=1, reloader_type="auto"):
326
+ """Run the given function in an independent python interpreter."""
327
+ import signal
328
+
329
+ reloader = reloader_loops[reloader_type](extra_files, interval)
330
+ signal.signal(signal.SIGTERM, lambda *args: sys.exit(0))
331
+ try:
332
+ if os.environ.get("WERKZEUG_RUN_MAIN") == "true":
333
+ ensure_echo_on()
334
+ t = threading.Thread(target=main_func, args=())
335
+ t.setDaemon(True)
336
+ t.start()
337
+ reloader.run()
338
+ else:
339
+ sys.exit(reloader.restart_with_reloader())
340
+ except KeyboardInterrupt:
341
+ pass