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.
- cavisson_pythonagent-0.0.1.dist-info/METADATA +32 -0
- cavisson_pythonagent-0.0.1.dist-info/RECORD +180 -0
- cavisson_pythonagent-0.0.1.dist-info/WHEEL +5 -0
- cavisson_pythonagent-0.0.1.dist-info/licenses/LICENSE +19 -0
- cavisson_pythonagent-0.0.1.dist-info/top_level.txt +1 -0
- pythonagent/__init__.py +22 -0
- pythonagent/agent/__init__.py +219 -0
- pythonagent/agent/internal/__init__.py +1 -0
- pythonagent/agent/internal/agent.py +1651 -0
- pythonagent/agent/internal/framesinfo.py +152 -0
- pythonagent/agent/internal/heap_dump.py +39 -0
- pythonagent/agent/internal/intercept_module.py +70 -0
- pythonagent/agent/internal/logs.py +122 -0
- pythonagent/agent/internal/metadata/__init__.py +0 -0
- pythonagent/agent/internal/metadata/agent_meta_data.py +276 -0
- pythonagent/agent/internal/proc_compat.py +75 -0
- pythonagent/agent/internal/profile.py +47 -0
- pythonagent/agent/internal/provider.py +83 -0
- pythonagent/agent/internal/thread_dump.py +85 -0
- pythonagent/agent/internal/udp.py +245 -0
- pythonagent/agent/internal/udp_message.py +800 -0
- pythonagent/agent/probes/Instrumentation/__init__.py +340 -0
- pythonagent/agent/probes/Instrumentation/find.py +243 -0
- pythonagent/agent/probes/Instrumentation/module_version_resolver.py +155 -0
- pythonagent/agent/probes/Instrumentation/new_parser.py +64 -0
- pythonagent/agent/probes/Instrumentation/parser.py +129 -0
- pythonagent/agent/probes/__init__.py +219 -0
- pythonagent/agent/probes/base.py +303 -0
- pythonagent/agent/probes/cache/__init__.py +51 -0
- pythonagent/agent/probes/cache/redis.py +119 -0
- pythonagent/agent/probes/cache/redis_asyncio.py +83 -0
- pythonagent/agent/probes/coroutines/__init__.py +1 -0
- pythonagent/agent/probes/coroutines/asyncio.py +63 -0
- pythonagent/agent/probes/elasticdb/__init__.py +7 -0
- pythonagent/agent/probes/elasticdb/aelastic.py +54 -0
- pythonagent/agent/probes/frameworks/__init__.py +27 -0
- pythonagent/agent/probes/frameworks/agentprofiler.py +105 -0
- pythonagent/agent/probes/frameworks/aiohttp_web.py +155 -0
- pythonagent/agent/probes/frameworks/aisess.py +151 -0
- pythonagent/agent/probes/frameworks/asgi.py +340 -0
- pythonagent/agent/probes/frameworks/bottle.py +27 -0
- pythonagent/agent/probes/frameworks/cherry.py +25 -0
- pythonagent/agent/probes/frameworks/django.py +128 -0
- pythonagent/agent/probes/frameworks/falcon.py +21 -0
- pythonagent/agent/probes/frameworks/fastapi.py +35 -0
- pythonagent/agent/probes/frameworks/flask.py +30 -0
- pythonagent/agent/probes/frameworks/pyramid.py +56 -0
- pythonagent/agent/probes/frameworks/test.py +108 -0
- pythonagent/agent/probes/frameworks/tornado_async_web.py +117 -0
- pythonagent/agent/probes/frameworks/tornado_web.py +133 -0
- pythonagent/agent/probes/frameworks/wsgi.py +353 -0
- pythonagent/agent/probes/grpc/__init__.py +76 -0
- pythonagent/agent/probes/grpc/client_interceptor.py +132 -0
- pythonagent/agent/probes/grpc/server_interceptor.py +129 -0
- pythonagent/agent/probes/havoc/__init__.py +0 -0
- pythonagent/agent/probes/havoc/custom_memory_stress.py +186 -0
- pythonagent/agent/probes/havoc/custom_thread_stress.py +187 -0
- pythonagent/agent/probes/havoc/havoc_constants.py +218 -0
- pythonagent/agent/probes/havoc/havoc_manager.py +981 -0
- pythonagent/agent/probes/http/__init__.py +49 -0
- pythonagent/agent/probes/http/aiohttp_client.py +59 -0
- pythonagent/agent/probes/http/boto.py +12 -0
- pythonagent/agent/probes/http/httplib.py +110 -0
- pythonagent/agent/probes/http/httpx_client.py +116 -0
- pythonagent/agent/probes/http/requests.py +15 -0
- pythonagent/agent/probes/http/tornado_httpclient.py +85 -0
- pythonagent/agent/probes/http/urllib3.py +16 -0
- pythonagent/agent/probes/langchain/__init__.py +21 -0
- pythonagent/agent/probes/langchain/base_tool.py +95 -0
- pythonagent/agent/probes/langchain/langchain_community.py +136 -0
- pythonagent/agent/probes/langchain/langchain_core.py +32 -0
- pythonagent/agent/probes/langchain/langchain_openai.py +110 -0
- pythonagent/agent/probes/logging/__init__.py +106 -0
- pythonagent/agent/probes/message_brokers/__init__.py +4 -0
- pythonagent/agent/probes/message_brokers/pika.py +126 -0
- pythonagent/agent/probes/mongodb/__init__.py +6 -0
- pythonagent/agent/probes/mongodb/pymongo.py +286 -0
- pythonagent/agent/probes/openai/__init__.py +3 -0
- pythonagent/agent/probes/openai/openai.py +797 -0
- pythonagent/agent/probes/span.py +101 -0
- pythonagent/agent/probes/sql/__init__.py +13 -0
- pythonagent/agent/probes/sql/botocores3.py +51 -0
- pythonagent/agent/probes/sql/dbapi.py +285 -0
- pythonagent/agent/probes/sql/dynamodb.py +90 -0
- pythonagent/agent/probes/sql/mysql_connector.py +24 -0
- pythonagent/agent/probes/sql/mysql_connector_cext.py +24 -0
- pythonagent/agent/probes/sql/mysqldb.py +43 -0
- pythonagent/agent/probes/sql/psycopg2.py +174 -0
- pythonagent/agent/probes/sql/pymysql.py +25 -0
- pythonagent/bootstrap/__init__.py +0 -0
- pythonagent/bootstrap/cav_gunicorn.py +26 -0
- pythonagent/bootstrap/cavagent_lambda_wrapper.py +291 -0
- pythonagent/bootstrap/run.py +47 -0
- pythonagent/bootstrap/sitecustomize.py +287 -0
- pythonagent/cavisson/netdiagnostics/CavAgent/instrumentationprofile.json +26 -0
- pythonagent/cavisson/netdiagnostics/CavAgent/interceptor_points.txt +29 -0
- pythonagent/cavisson/netdiagnostics/python/CavAgent/instrumentationprofile.json +42 -0
- pythonagent/cavisson/netdiagnostics/python/CavAgent/interceptor_points.txt +29 -0
- pythonagent/cavisson/netdiagnostics/python/config/ndsettings.conf +6 -0
- pythonagent/config.py +279 -0
- pythonagent/find.py +72 -0
- pythonagent/find_mod_cls_name.py +54 -0
- pythonagent/lang.py +131 -0
- pythonagent/lib.py +91 -0
- pythonagent/main/__init__.py +0 -0
- pythonagent/main/pytrace/__init__.py +79 -0
- pythonagent/main/pytrace/commands/__init__.py +0 -0
- pythonagent/main/pytrace/commands/auto_discovery.py +25 -0
- pythonagent/main/pytrace/commands/run.py +401 -0
- pythonagent/main/pytrace/pytrace.py +133 -0
- pythonagent/main/wsgi.py +6 -0
- pythonagent/main.py +27 -0
- pythonagent/run.py +46 -0
- pythonagent/sqins.py +8 -0
- pythonagent/test.py +73 -0
- pythonagent/utils.py +168 -0
- pythonagent/vendor/__init__.py +0 -0
- pythonagent/vendor/pympler/__init__.py +1 -0
- pythonagent/vendor/pympler/asizeof.py +2810 -0
- pythonagent/vendor/pympler/charts.py +62 -0
- pythonagent/vendor/pympler/classtracker.py +590 -0
- pythonagent/vendor/pympler/classtracker_stats.py +780 -0
- pythonagent/vendor/pympler/garbagegraph.py +80 -0
- pythonagent/vendor/pympler/mprofile.py +97 -0
- pythonagent/vendor/pympler/muppy.py +275 -0
- pythonagent/vendor/pympler/panels.py +115 -0
- pythonagent/vendor/pympler/process.py +238 -0
- pythonagent/vendor/pympler/py.typed +0 -0
- pythonagent/vendor/pympler/refbrowser.py +451 -0
- pythonagent/vendor/pympler/refgraph.py +350 -0
- pythonagent/vendor/pympler/summary.py +321 -0
- pythonagent/vendor/pympler/tracker.py +267 -0
- pythonagent/vendor/pympler/util/__init__.py +0 -0
- pythonagent/vendor/pympler/util/bottle.py +3809 -0
- pythonagent/vendor/pympler/util/compat.py +23 -0
- pythonagent/vendor/pympler/util/stringutils.py +77 -0
- pythonagent/vendor/pympler/web.py +346 -0
- pythonagent/vendor/werkzeug/__init__.py +20 -0
- pythonagent/vendor/werkzeug/_compat.py +228 -0
- pythonagent/vendor/werkzeug/_internal.py +473 -0
- pythonagent/vendor/werkzeug/_reloader.py +341 -0
- pythonagent/vendor/werkzeug/datastructures.py +3120 -0
- pythonagent/vendor/werkzeug/debug/__init__.py +498 -0
- pythonagent/vendor/werkzeug/debug/console.py +218 -0
- pythonagent/vendor/werkzeug/debug/repr.py +297 -0
- pythonagent/vendor/werkzeug/debug/tbtools.py +628 -0
- pythonagent/vendor/werkzeug/exceptions.py +829 -0
- pythonagent/vendor/werkzeug/filesystem.py +64 -0
- pythonagent/vendor/werkzeug/formparser.py +584 -0
- pythonagent/vendor/werkzeug/http.py +1307 -0
- pythonagent/vendor/werkzeug/local.py +420 -0
- pythonagent/vendor/werkzeug/middleware/__init__.py +25 -0
- pythonagent/vendor/werkzeug/middleware/dispatcher.py +66 -0
- pythonagent/vendor/werkzeug/middleware/http_proxy.py +219 -0
- pythonagent/vendor/werkzeug/middleware/lint.py +408 -0
- pythonagent/vendor/werkzeug/middleware/profiler.py +132 -0
- pythonagent/vendor/werkzeug/middleware/proxy_fix.py +169 -0
- pythonagent/vendor/werkzeug/middleware/shared_data.py +293 -0
- pythonagent/vendor/werkzeug/posixemulation.py +117 -0
- pythonagent/vendor/werkzeug/routing.py +2210 -0
- pythonagent/vendor/werkzeug/security.py +249 -0
- pythonagent/vendor/werkzeug/serving.py +1117 -0
- pythonagent/vendor/werkzeug/test.py +1123 -0
- pythonagent/vendor/werkzeug/testapp.py +241 -0
- pythonagent/vendor/werkzeug/urls.py +1138 -0
- pythonagent/vendor/werkzeug/useragents.py +202 -0
- pythonagent/vendor/werkzeug/utils.py +778 -0
- pythonagent/vendor/werkzeug/wrappers/__init__.py +36 -0
- pythonagent/vendor/werkzeug/wrappers/accept.py +50 -0
- pythonagent/vendor/werkzeug/wrappers/auth.py +33 -0
- pythonagent/vendor/werkzeug/wrappers/base_request.py +673 -0
- pythonagent/vendor/werkzeug/wrappers/base_response.py +700 -0
- pythonagent/vendor/werkzeug/wrappers/common_descriptors.py +341 -0
- pythonagent/vendor/werkzeug/wrappers/cors.py +100 -0
- pythonagent/vendor/werkzeug/wrappers/etag.py +304 -0
- pythonagent/vendor/werkzeug/wrappers/json.py +145 -0
- pythonagent/vendor/werkzeug/wrappers/request.py +49 -0
- pythonagent/vendor/werkzeug/wrappers/response.py +84 -0
- pythonagent/vendor/werkzeug/wrappers/user_agent.py +14 -0
- pythonagent/vendor/werkzeug/wsgi.py +1000 -0
|
@@ -0,0 +1,628 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
werkzeug.debug.tbtools
|
|
4
|
+
~~~~~~~~~~~~~~~~~~~~~~
|
|
5
|
+
|
|
6
|
+
This module provides various traceback related utility functions.
|
|
7
|
+
|
|
8
|
+
:copyright: 2007 Pallets
|
|
9
|
+
:license: BSD-3-Clause
|
|
10
|
+
"""
|
|
11
|
+
import codecs
|
|
12
|
+
import inspect
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
import re
|
|
16
|
+
import sys
|
|
17
|
+
import sysconfig
|
|
18
|
+
import traceback
|
|
19
|
+
from tokenize import TokenError
|
|
20
|
+
|
|
21
|
+
from .._compat import PY2
|
|
22
|
+
from .._compat import range_type
|
|
23
|
+
from .._compat import reraise
|
|
24
|
+
from .._compat import string_types
|
|
25
|
+
from .._compat import text_type
|
|
26
|
+
from .._compat import to_native
|
|
27
|
+
from .._compat import to_unicode
|
|
28
|
+
from ..filesystem import get_filesystem_encoding
|
|
29
|
+
from ..utils import cached_property
|
|
30
|
+
from ..utils import escape
|
|
31
|
+
from .console import Console
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
_coding_re = re.compile(br"coding[:=]\s*([-\w.]+)")
|
|
35
|
+
_line_re = re.compile(br"^(.*?)$", re.MULTILINE)
|
|
36
|
+
_funcdef_re = re.compile(r"^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)")
|
|
37
|
+
UTF8_COOKIE = b"\xef\xbb\xbf"
|
|
38
|
+
|
|
39
|
+
system_exceptions = (SystemExit, KeyboardInterrupt)
|
|
40
|
+
try:
|
|
41
|
+
system_exceptions += (GeneratorExit,)
|
|
42
|
+
except NameError:
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
HEADER = u"""\
|
|
47
|
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
|
48
|
+
"http://www.w3.org/TR/html4/loose.dtd">
|
|
49
|
+
<html>
|
|
50
|
+
<head>
|
|
51
|
+
<title>%(title)s // Werkzeug Debugger</title>
|
|
52
|
+
<link rel="stylesheet" href="?__debugger__=yes&cmd=resource&f=style.css"
|
|
53
|
+
type="text/css">
|
|
54
|
+
<!-- We need to make sure this has a favicon so that the debugger does
|
|
55
|
+
not by accident trigger a request to /favicon.ico which might
|
|
56
|
+
change the application state. -->
|
|
57
|
+
<link rel="shortcut icon"
|
|
58
|
+
href="?__debugger__=yes&cmd=resource&f=console.png">
|
|
59
|
+
<script src="?__debugger__=yes&cmd=resource&f=jquery.js"></script>
|
|
60
|
+
<script src="?__debugger__=yes&cmd=resource&f=debugger.js"></script>
|
|
61
|
+
<script type="text/javascript">
|
|
62
|
+
var TRACEBACK = %(traceback_id)d,
|
|
63
|
+
CONSOLE_MODE = %(console)s,
|
|
64
|
+
EVALEX = %(evalex)s,
|
|
65
|
+
EVALEX_TRUSTED = %(evalex_trusted)s,
|
|
66
|
+
SECRET = "%(secret)s";
|
|
67
|
+
</script>
|
|
68
|
+
</head>
|
|
69
|
+
<body style="background-color: #fff">
|
|
70
|
+
<div class="debugger">
|
|
71
|
+
"""
|
|
72
|
+
FOOTER = u"""\
|
|
73
|
+
<div class="footer">
|
|
74
|
+
Brought to you by <strong class="arthur">DON'T PANIC</strong>, your
|
|
75
|
+
friendly Werkzeug powered traceback interpreter.
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div class="pin-prompt">
|
|
80
|
+
<div class="inner">
|
|
81
|
+
<h3>Console Locked</h3>
|
|
82
|
+
<p>
|
|
83
|
+
The console is locked and needs to be unlocked by entering the PIN.
|
|
84
|
+
You can find the PIN printed out on the standard output of your
|
|
85
|
+
shell that runs the server.
|
|
86
|
+
<form>
|
|
87
|
+
<p>PIN:
|
|
88
|
+
<input type=text name=pin size=14>
|
|
89
|
+
<input type=submit name=btn value="Confirm Pin">
|
|
90
|
+
</form>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
</body>
|
|
94
|
+
</html>
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
PAGE_HTML = (
|
|
98
|
+
HEADER
|
|
99
|
+
+ u"""\
|
|
100
|
+
<h1>%(exception_type)s</h1>
|
|
101
|
+
<div class="detail">
|
|
102
|
+
<p class="errormsg">%(exception)s</p>
|
|
103
|
+
</div>
|
|
104
|
+
<h2 class="traceback">Traceback <em>(most recent call last)</em></h2>
|
|
105
|
+
%(summary)s
|
|
106
|
+
<div class="plain">
|
|
107
|
+
<form action="/?__debugger__=yes&cmd=paste" method="post">
|
|
108
|
+
<p>
|
|
109
|
+
<input type="hidden" name="language" value="pytb">
|
|
110
|
+
This is the Copy/Paste friendly version of the traceback. <span
|
|
111
|
+
class="pastemessage">You can also paste this traceback into
|
|
112
|
+
a <a href="https://gist.github.com/">gist</a>:
|
|
113
|
+
<input type="submit" value="create paste"></span>
|
|
114
|
+
</p>
|
|
115
|
+
<textarea cols="50" rows="10" name="code" readonly>%(plaintext)s</textarea>
|
|
116
|
+
</form>
|
|
117
|
+
</div>
|
|
118
|
+
<div class="explanation">
|
|
119
|
+
The debugger caught an exception in your WSGI application. You can now
|
|
120
|
+
look at the traceback which led to the error. <span class="nojavascript">
|
|
121
|
+
If you enable JavaScript you can also use additional features such as code
|
|
122
|
+
execution (if the evalex feature is enabled), automatic pasting of the
|
|
123
|
+
exceptions and much more.</span>
|
|
124
|
+
</div>
|
|
125
|
+
"""
|
|
126
|
+
+ FOOTER
|
|
127
|
+
+ """
|
|
128
|
+
<!--
|
|
129
|
+
|
|
130
|
+
%(plaintext_cs)s
|
|
131
|
+
|
|
132
|
+
-->
|
|
133
|
+
"""
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
CONSOLE_HTML = (
|
|
137
|
+
HEADER
|
|
138
|
+
+ u"""\
|
|
139
|
+
<h1>Interactive Console</h1>
|
|
140
|
+
<div class="explanation">
|
|
141
|
+
In this console you can execute Python expressions in the context of the
|
|
142
|
+
application. The initial namespace was created by the debugger automatically.
|
|
143
|
+
</div>
|
|
144
|
+
<div class="console"><div class="inner">The Console requires JavaScript.</div></div>
|
|
145
|
+
"""
|
|
146
|
+
+ FOOTER
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
SUMMARY_HTML = u"""\
|
|
150
|
+
<div class="%(classes)s">
|
|
151
|
+
%(title)s
|
|
152
|
+
<ul>%(frames)s</ul>
|
|
153
|
+
%(description)s
|
|
154
|
+
</div>
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
FRAME_HTML = u"""\
|
|
158
|
+
<div class="frame" id="frame-%(id)d">
|
|
159
|
+
<h4>File <cite class="filename">"%(filename)s"</cite>,
|
|
160
|
+
line <em class="line">%(lineno)s</em>,
|
|
161
|
+
in <code class="function">%(function_name)s</code></h4>
|
|
162
|
+
<div class="source %(library)s">%(lines)s</div>
|
|
163
|
+
</div>
|
|
164
|
+
"""
|
|
165
|
+
|
|
166
|
+
SOURCE_LINE_HTML = u"""\
|
|
167
|
+
<tr class="%(classes)s">
|
|
168
|
+
<td class=lineno>%(lineno)s</td>
|
|
169
|
+
<td>%(code)s</td>
|
|
170
|
+
</tr>
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def render_console_html(secret, evalex_trusted=True):
|
|
175
|
+
return CONSOLE_HTML % {
|
|
176
|
+
"evalex": "true",
|
|
177
|
+
"evalex_trusted": "true" if evalex_trusted else "false",
|
|
178
|
+
"console": "true",
|
|
179
|
+
"title": "Console",
|
|
180
|
+
"secret": secret,
|
|
181
|
+
"traceback_id": -1,
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def get_current_traceback(
|
|
186
|
+
ignore_system_exceptions=False, show_hidden_frames=False, skip=0
|
|
187
|
+
):
|
|
188
|
+
"""Get the current exception info as `Traceback` object. Per default
|
|
189
|
+
calling this method will reraise system exceptions such as generator exit,
|
|
190
|
+
system exit or others. This behavior can be disabled by passing `False`
|
|
191
|
+
to the function as first parameter.
|
|
192
|
+
"""
|
|
193
|
+
exc_type, exc_value, tb = sys.exc_info()
|
|
194
|
+
if ignore_system_exceptions and exc_type in system_exceptions:
|
|
195
|
+
reraise(exc_type, exc_value, tb)
|
|
196
|
+
for _ in range_type(skip):
|
|
197
|
+
if tb.tb_next is None:
|
|
198
|
+
break
|
|
199
|
+
tb = tb.tb_next
|
|
200
|
+
tb = Traceback(exc_type, exc_value, tb)
|
|
201
|
+
if not show_hidden_frames:
|
|
202
|
+
tb.filter_hidden_frames()
|
|
203
|
+
return tb
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
class Line(object):
|
|
207
|
+
"""Helper for the source renderer."""
|
|
208
|
+
|
|
209
|
+
__slots__ = ("lineno", "code", "in_frame", "current")
|
|
210
|
+
|
|
211
|
+
def __init__(self, lineno, code):
|
|
212
|
+
self.lineno = lineno
|
|
213
|
+
self.code = code
|
|
214
|
+
self.in_frame = False
|
|
215
|
+
self.current = False
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def classes(self):
|
|
219
|
+
rv = ["line"]
|
|
220
|
+
if self.in_frame:
|
|
221
|
+
rv.append("in-frame")
|
|
222
|
+
if self.current:
|
|
223
|
+
rv.append("current")
|
|
224
|
+
return rv
|
|
225
|
+
|
|
226
|
+
def render(self):
|
|
227
|
+
return SOURCE_LINE_HTML % {
|
|
228
|
+
"classes": u" ".join(self.classes),
|
|
229
|
+
"lineno": self.lineno,
|
|
230
|
+
"code": escape(self.code),
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class Traceback(object):
|
|
235
|
+
"""Wraps a traceback."""
|
|
236
|
+
|
|
237
|
+
def __init__(self, exc_type, exc_value, tb):
|
|
238
|
+
self.exc_type = exc_type
|
|
239
|
+
self.exc_value = exc_value
|
|
240
|
+
self.tb = tb
|
|
241
|
+
|
|
242
|
+
exception_type = exc_type.__name__
|
|
243
|
+
if exc_type.__module__ not in {"builtins", "__builtin__", "exceptions"}:
|
|
244
|
+
exception_type = exc_type.__module__ + "." + exception_type
|
|
245
|
+
self.exception_type = exception_type
|
|
246
|
+
|
|
247
|
+
self.groups = []
|
|
248
|
+
memo = set()
|
|
249
|
+
while True:
|
|
250
|
+
self.groups.append(Group(exc_type, exc_value, tb))
|
|
251
|
+
memo.add(id(exc_value))
|
|
252
|
+
if PY2:
|
|
253
|
+
break
|
|
254
|
+
exc_value = exc_value.__cause__ or exc_value.__context__
|
|
255
|
+
if exc_value is None or id(exc_value) in memo:
|
|
256
|
+
break
|
|
257
|
+
exc_type = type(exc_value)
|
|
258
|
+
tb = exc_value.__traceback__
|
|
259
|
+
self.groups.reverse()
|
|
260
|
+
self.frames = [frame for group in self.groups for frame in group.frames]
|
|
261
|
+
|
|
262
|
+
def filter_hidden_frames(self):
|
|
263
|
+
"""Remove the frames according to the paste spec."""
|
|
264
|
+
for group in self.groups:
|
|
265
|
+
group.filter_hidden_frames()
|
|
266
|
+
|
|
267
|
+
self.frames[:] = [frame for group in self.groups for frame in group.frames]
|
|
268
|
+
|
|
269
|
+
@property
|
|
270
|
+
def is_syntax_error(self):
|
|
271
|
+
"""Is it a syntax error?"""
|
|
272
|
+
return isinstance(self.exc_value, SyntaxError)
|
|
273
|
+
|
|
274
|
+
@property
|
|
275
|
+
def exception(self):
|
|
276
|
+
"""String representation of the final exception."""
|
|
277
|
+
return self.groups[-1].exception
|
|
278
|
+
|
|
279
|
+
def log(self, logfile=None):
|
|
280
|
+
"""Log the ASCII traceback into a file object."""
|
|
281
|
+
if logfile is None:
|
|
282
|
+
logfile = sys.stderr
|
|
283
|
+
tb = self.plaintext.rstrip() + u"\n"
|
|
284
|
+
logfile.write(to_native(tb, "utf-8", "replace"))
|
|
285
|
+
|
|
286
|
+
def paste(self):
|
|
287
|
+
"""Create a paste and return the paste id."""
|
|
288
|
+
data = json.dumps(
|
|
289
|
+
{
|
|
290
|
+
"description": "Werkzeug Internal Server Error",
|
|
291
|
+
"public": False,
|
|
292
|
+
"files": {"traceback.txt": {"content": self.plaintext}},
|
|
293
|
+
}
|
|
294
|
+
).encode("utf-8")
|
|
295
|
+
try:
|
|
296
|
+
from urllib2 import urlopen
|
|
297
|
+
except ImportError:
|
|
298
|
+
from urllib.request import urlopen
|
|
299
|
+
rv = urlopen("https://api.github.com/gists", data=data)
|
|
300
|
+
resp = json.loads(rv.read().decode("utf-8"))
|
|
301
|
+
rv.close()
|
|
302
|
+
return {"url": resp["html_url"], "id": resp["id"]}
|
|
303
|
+
|
|
304
|
+
def render_summary(self, include_title=True):
|
|
305
|
+
"""Render the traceback for the interactive console."""
|
|
306
|
+
title = ""
|
|
307
|
+
classes = ["traceback"]
|
|
308
|
+
if not self.frames:
|
|
309
|
+
classes.append("noframe-traceback")
|
|
310
|
+
frames = []
|
|
311
|
+
else:
|
|
312
|
+
library_frames = sum(frame.is_library for frame in self.frames)
|
|
313
|
+
mark_lib = 0 < library_frames < len(self.frames)
|
|
314
|
+
frames = [group.render(mark_lib=mark_lib) for group in self.groups]
|
|
315
|
+
|
|
316
|
+
if include_title:
|
|
317
|
+
if self.is_syntax_error:
|
|
318
|
+
title = u"Syntax Error"
|
|
319
|
+
else:
|
|
320
|
+
title = u"Traceback <em>(most recent call last)</em>:"
|
|
321
|
+
|
|
322
|
+
if self.is_syntax_error:
|
|
323
|
+
description_wrapper = u"<pre class=syntaxerror>%s</pre>"
|
|
324
|
+
else:
|
|
325
|
+
description_wrapper = u"<blockquote>%s</blockquote>"
|
|
326
|
+
|
|
327
|
+
return SUMMARY_HTML % {
|
|
328
|
+
"classes": u" ".join(classes),
|
|
329
|
+
"title": u"<h3>%s</h3>" % title if title else u"",
|
|
330
|
+
"frames": u"\n".join(frames),
|
|
331
|
+
"description": description_wrapper % escape(self.exception),
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
def render_full(self, evalex=False, secret=None, evalex_trusted=True):
|
|
335
|
+
"""Render the Full HTML page with the traceback info."""
|
|
336
|
+
exc = escape(self.exception)
|
|
337
|
+
return PAGE_HTML % {
|
|
338
|
+
"evalex": "true" if evalex else "false",
|
|
339
|
+
"evalex_trusted": "true" if evalex_trusted else "false",
|
|
340
|
+
"console": "false",
|
|
341
|
+
"title": exc,
|
|
342
|
+
"exception": exc,
|
|
343
|
+
"exception_type": escape(self.exception_type),
|
|
344
|
+
"summary": self.render_summary(include_title=False),
|
|
345
|
+
"plaintext": escape(self.plaintext),
|
|
346
|
+
"plaintext_cs": re.sub("-{2,}", "-", self.plaintext),
|
|
347
|
+
"traceback_id": self.id,
|
|
348
|
+
"secret": secret,
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
@cached_property
|
|
352
|
+
def plaintext(self):
|
|
353
|
+
return u"\n".join([group.render_text() for group in self.groups])
|
|
354
|
+
|
|
355
|
+
@property
|
|
356
|
+
def id(self):
|
|
357
|
+
return id(self)
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
class Group(object):
|
|
361
|
+
"""A group of frames for an exception in a traceback. On Python 3,
|
|
362
|
+
if the exception has a ``__cause__`` or ``__context__``, there are
|
|
363
|
+
multiple exception groups.
|
|
364
|
+
"""
|
|
365
|
+
|
|
366
|
+
def __init__(self, exc_type, exc_value, tb):
|
|
367
|
+
self.exc_type = exc_type
|
|
368
|
+
self.exc_value = exc_value
|
|
369
|
+
self.info = None
|
|
370
|
+
if not PY2:
|
|
371
|
+
if exc_value.__cause__ is not None:
|
|
372
|
+
self.info = (
|
|
373
|
+
u"The above exception was the direct cause of the"
|
|
374
|
+
u" following exception"
|
|
375
|
+
)
|
|
376
|
+
elif exc_value.__context__ is not None:
|
|
377
|
+
self.info = (
|
|
378
|
+
u"During handling of the above exception, another"
|
|
379
|
+
u" exception occurred"
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
self.frames = []
|
|
383
|
+
while tb is not None:
|
|
384
|
+
self.frames.append(Frame(exc_type, exc_value, tb))
|
|
385
|
+
tb = tb.tb_next
|
|
386
|
+
|
|
387
|
+
def filter_hidden_frames(self):
|
|
388
|
+
new_frames = []
|
|
389
|
+
hidden = False
|
|
390
|
+
|
|
391
|
+
for frame in self.frames:
|
|
392
|
+
hide = frame.hide
|
|
393
|
+
if hide in ("before", "before_and_this"):
|
|
394
|
+
new_frames = []
|
|
395
|
+
hidden = False
|
|
396
|
+
if hide == "before_and_this":
|
|
397
|
+
continue
|
|
398
|
+
elif hide in ("reset", "reset_and_this"):
|
|
399
|
+
hidden = False
|
|
400
|
+
if hide == "reset_and_this":
|
|
401
|
+
continue
|
|
402
|
+
elif hide in ("after", "after_and_this"):
|
|
403
|
+
hidden = True
|
|
404
|
+
if hide == "after_and_this":
|
|
405
|
+
continue
|
|
406
|
+
elif hide or hidden:
|
|
407
|
+
continue
|
|
408
|
+
new_frames.append(frame)
|
|
409
|
+
|
|
410
|
+
# if we only have one frame and that frame is from the codeop
|
|
411
|
+
# module, remove it.
|
|
412
|
+
if len(new_frames) == 1 and self.frames[0].module == "codeop":
|
|
413
|
+
del self.frames[:]
|
|
414
|
+
|
|
415
|
+
# if the last frame is missing something went terrible wrong :(
|
|
416
|
+
elif self.frames[-1] in new_frames:
|
|
417
|
+
self.frames[:] = new_frames
|
|
418
|
+
|
|
419
|
+
@property
|
|
420
|
+
def exception(self):
|
|
421
|
+
"""String representation of the exception."""
|
|
422
|
+
buf = traceback.format_exception_only(self.exc_type, self.exc_value)
|
|
423
|
+
rv = "".join(buf).strip()
|
|
424
|
+
return to_unicode(rv, "utf-8", "replace")
|
|
425
|
+
|
|
426
|
+
def render(self, mark_lib=True):
|
|
427
|
+
out = []
|
|
428
|
+
if self.info is not None:
|
|
429
|
+
out.append(u'<li><div class="exc-divider">%s:</div>' % self.info)
|
|
430
|
+
for frame in self.frames:
|
|
431
|
+
out.append(
|
|
432
|
+
u"<li%s>%s"
|
|
433
|
+
% (
|
|
434
|
+
u' title="%s"' % escape(frame.info) if frame.info else u"",
|
|
435
|
+
frame.render(mark_lib=mark_lib),
|
|
436
|
+
)
|
|
437
|
+
)
|
|
438
|
+
return u"\n".join(out)
|
|
439
|
+
|
|
440
|
+
def render_text(self):
|
|
441
|
+
out = []
|
|
442
|
+
if self.info is not None:
|
|
443
|
+
out.append(u"\n%s:\n" % self.info)
|
|
444
|
+
out.append(u"Traceback (most recent call last):")
|
|
445
|
+
for frame in self.frames:
|
|
446
|
+
out.append(frame.render_text())
|
|
447
|
+
out.append(self.exception)
|
|
448
|
+
return u"\n".join(out)
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
class Frame(object):
|
|
452
|
+
"""A single frame in a traceback."""
|
|
453
|
+
|
|
454
|
+
def __init__(self, exc_type, exc_value, tb):
|
|
455
|
+
self.lineno = tb.tb_lineno
|
|
456
|
+
self.function_name = tb.tb_frame.f_code.co_name
|
|
457
|
+
self.locals = tb.tb_frame.f_locals
|
|
458
|
+
self.globals = tb.tb_frame.f_globals
|
|
459
|
+
|
|
460
|
+
fn = inspect.getsourcefile(tb) or inspect.getfile(tb)
|
|
461
|
+
if fn[-4:] in (".pyo", ".pyc"):
|
|
462
|
+
fn = fn[:-1]
|
|
463
|
+
# if it's a file on the file system resolve the real filename.
|
|
464
|
+
if os.path.isfile(fn):
|
|
465
|
+
fn = os.path.realpath(fn)
|
|
466
|
+
self.filename = to_unicode(fn, get_filesystem_encoding())
|
|
467
|
+
self.module = self.globals.get("__name__", self.locals.get("__name__"))
|
|
468
|
+
self.loader = self.globals.get("__loader__", self.locals.get("__loader__"))
|
|
469
|
+
self.code = tb.tb_frame.f_code
|
|
470
|
+
|
|
471
|
+
# support for paste's traceback extensions
|
|
472
|
+
self.hide = self.locals.get("__traceback_hide__", False)
|
|
473
|
+
info = self.locals.get("__traceback_info__")
|
|
474
|
+
if info is not None:
|
|
475
|
+
info = to_unicode(info, "utf-8", "replace")
|
|
476
|
+
self.info = info
|
|
477
|
+
|
|
478
|
+
def render(self, mark_lib=True):
|
|
479
|
+
"""Render a single frame in a traceback."""
|
|
480
|
+
return FRAME_HTML % {
|
|
481
|
+
"id": self.id,
|
|
482
|
+
"filename": escape(self.filename),
|
|
483
|
+
"lineno": self.lineno,
|
|
484
|
+
"function_name": escape(self.function_name),
|
|
485
|
+
"lines": self.render_line_context(),
|
|
486
|
+
"library": "library" if mark_lib and self.is_library else "",
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
@cached_property
|
|
490
|
+
def is_library(self):
|
|
491
|
+
return any(
|
|
492
|
+
self.filename.startswith(path) for path in sysconfig.get_paths().values()
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
def render_text(self):
|
|
496
|
+
return u' File "%s", line %s, in %s\n %s' % (
|
|
497
|
+
self.filename,
|
|
498
|
+
self.lineno,
|
|
499
|
+
self.function_name,
|
|
500
|
+
self.current_line.strip(),
|
|
501
|
+
)
|
|
502
|
+
|
|
503
|
+
def render_line_context(self):
|
|
504
|
+
before, current, after = self.get_context_lines()
|
|
505
|
+
rv = []
|
|
506
|
+
|
|
507
|
+
def render_line(line, cls):
|
|
508
|
+
line = line.expandtabs().rstrip()
|
|
509
|
+
stripped_line = line.strip()
|
|
510
|
+
prefix = len(line) - len(stripped_line)
|
|
511
|
+
rv.append(
|
|
512
|
+
'<pre class="line %s"><span class="ws">%s</span>%s</pre>'
|
|
513
|
+
% (cls, " " * prefix, escape(stripped_line) or " ")
|
|
514
|
+
)
|
|
515
|
+
|
|
516
|
+
for line in before:
|
|
517
|
+
render_line(line, "before")
|
|
518
|
+
render_line(current, "current")
|
|
519
|
+
for line in after:
|
|
520
|
+
render_line(line, "after")
|
|
521
|
+
|
|
522
|
+
return "\n".join(rv)
|
|
523
|
+
|
|
524
|
+
def get_annotated_lines(self):
|
|
525
|
+
"""Helper function that returns lines with extra information."""
|
|
526
|
+
lines = [Line(idx + 1, x) for idx, x in enumerate(self.sourcelines)]
|
|
527
|
+
|
|
528
|
+
# find function definition and mark lines
|
|
529
|
+
if hasattr(self.code, "co_firstlineno"):
|
|
530
|
+
lineno = self.code.co_firstlineno - 1
|
|
531
|
+
while lineno > 0:
|
|
532
|
+
if _funcdef_re.match(lines[lineno].code):
|
|
533
|
+
break
|
|
534
|
+
lineno -= 1
|
|
535
|
+
try:
|
|
536
|
+
offset = len(inspect.getblock([x.code + "\n" for x in lines[lineno:]]))
|
|
537
|
+
except TokenError:
|
|
538
|
+
offset = 0
|
|
539
|
+
for line in lines[lineno : lineno + offset]:
|
|
540
|
+
line.in_frame = True
|
|
541
|
+
|
|
542
|
+
# mark current line
|
|
543
|
+
try:
|
|
544
|
+
lines[self.lineno - 1].current = True
|
|
545
|
+
except IndexError:
|
|
546
|
+
pass
|
|
547
|
+
|
|
548
|
+
return lines
|
|
549
|
+
|
|
550
|
+
def eval(self, code, mode="single"):
|
|
551
|
+
"""Evaluate code in the context of the frame."""
|
|
552
|
+
if isinstance(code, string_types):
|
|
553
|
+
if PY2 and isinstance(code, text_type): # noqa
|
|
554
|
+
code = UTF8_COOKIE + code.encode("utf-8")
|
|
555
|
+
code = compile(code, "<interactive>", mode)
|
|
556
|
+
return eval(code, self.globals, self.locals)
|
|
557
|
+
|
|
558
|
+
@cached_property
|
|
559
|
+
def sourcelines(self):
|
|
560
|
+
"""The sourcecode of the file as list of unicode strings."""
|
|
561
|
+
# get sourcecode from loader or file
|
|
562
|
+
source = None
|
|
563
|
+
if self.loader is not None:
|
|
564
|
+
try:
|
|
565
|
+
if hasattr(self.loader, "get_source"):
|
|
566
|
+
source = self.loader.get_source(self.module)
|
|
567
|
+
elif hasattr(self.loader, "get_source_by_code"):
|
|
568
|
+
source = self.loader.get_source_by_code(self.code)
|
|
569
|
+
except Exception:
|
|
570
|
+
# we munch the exception so that we don't cause troubles
|
|
571
|
+
# if the loader is broken.
|
|
572
|
+
pass
|
|
573
|
+
|
|
574
|
+
if source is None:
|
|
575
|
+
try:
|
|
576
|
+
with open(
|
|
577
|
+
to_native(self.filename, get_filesystem_encoding()), mode="rb"
|
|
578
|
+
) as f:
|
|
579
|
+
source = f.read()
|
|
580
|
+
except IOError:
|
|
581
|
+
return []
|
|
582
|
+
|
|
583
|
+
# already unicode? return right away
|
|
584
|
+
if isinstance(source, text_type):
|
|
585
|
+
return source.splitlines()
|
|
586
|
+
|
|
587
|
+
# yes. it should be ascii, but we don't want to reject too many
|
|
588
|
+
# characters in the debugger if something breaks
|
|
589
|
+
charset = "utf-8"
|
|
590
|
+
if source.startswith(UTF8_COOKIE):
|
|
591
|
+
source = source[3:]
|
|
592
|
+
else:
|
|
593
|
+
for idx, match in enumerate(_line_re.finditer(source)):
|
|
594
|
+
match = _coding_re.search(match.group())
|
|
595
|
+
if match is not None:
|
|
596
|
+
charset = match.group(1)
|
|
597
|
+
break
|
|
598
|
+
if idx > 1:
|
|
599
|
+
break
|
|
600
|
+
|
|
601
|
+
# on broken cookies we fall back to utf-8 too
|
|
602
|
+
charset = to_native(charset)
|
|
603
|
+
try:
|
|
604
|
+
codecs.lookup(charset)
|
|
605
|
+
except LookupError:
|
|
606
|
+
charset = "utf-8"
|
|
607
|
+
|
|
608
|
+
return source.decode(charset, "replace").splitlines()
|
|
609
|
+
|
|
610
|
+
def get_context_lines(self, context=5):
|
|
611
|
+
before = self.sourcelines[self.lineno - context - 1 : self.lineno - 1]
|
|
612
|
+
past = self.sourcelines[self.lineno : self.lineno + context]
|
|
613
|
+
return (before, self.current_line, past)
|
|
614
|
+
|
|
615
|
+
@property
|
|
616
|
+
def current_line(self):
|
|
617
|
+
try:
|
|
618
|
+
return self.sourcelines[self.lineno - 1]
|
|
619
|
+
except IndexError:
|
|
620
|
+
return u""
|
|
621
|
+
|
|
622
|
+
@cached_property
|
|
623
|
+
def console(self):
|
|
624
|
+
return Console(self.globals, self.locals)
|
|
625
|
+
|
|
626
|
+
@property
|
|
627
|
+
def id(self):
|
|
628
|
+
return id(self)
|