WebError Traceback:
>> | Display the lines of code near each part of the traceback |
![]() | Show a debug prompt to allow you to directly debug the code at the traceback |
`` and multiple spaces to use `` ``). If ``quote`` is true, then the value will be HTML quoted first. """ if quote: v = html_quote(v) v = v.replace('\n', '
\n') v = re.sub(r'()( +)', _repl_nbsp, v) v = re.sub(r'(\n)( +)', _repl_nbsp, v) v = re.sub(r'^()( +)', _repl_nbsp, v) return '
%s
' % v
def _repl_nbsp(match):
if len(match.group(2)) == 1:
return ' '
return match.group(1) + ' ' * (len(match.group(2))-1) + ' '
def simplecatcher(application):
"""
A simple middleware that catches errors and turns them into simple
tracebacks.
"""
def simplecatcher_app(environ, start_response):
try:
return application(environ, start_response)
except:
out = StringIO()
traceback.print_exc(file=out)
start_response('500 Server Error',
[('content-type', 'text/html')],
sys.exc_info())
res = out.getvalue()
return ['Error
%s' % html_quote(res)] return simplecatcher_app def wsgiapp(): """ Turns a function or method into a WSGI application. """ def decorator(func): def wsgiapp_wrapper(*args): # we get 3 args when this is a method, two when it is # a function :( if len(args) == 3: environ = args[1] start_response = args[2] args = [args[0]] else: environ, start_response = args args = [] def application(environ, start_response): form = request.parse_formvars(environ, include_get_vars=True) status = '200 OK' form['environ'] = environ try: res = func(*args, **form.mixed()) except ValueError, ve: status = '500 Server Error' res = 'There was an error: %s' % \ html_quote(ve) start_response(status, [('content-type', 'text/html')]) return [res] app = simplecatcher(application) return app(environ, start_response) wsgiapp_wrapper.exposed = True return wsgiapp_wrapper return decorator def get_debug_info(func): """ A decorator (meant to be used under ``wsgiapp()``) that resolves the ``debugcount`` variable to a ``DebugInfo`` object (or gives an error if it can't be found). """ def debug_info_replacement(self, req): if 'debugcount' not in req.params: return exc.HTTPBadRequest( "You must provide a debugcount parameter") debugcount = req.params['debugcount'] try: debugcount = int(debugcount) except ValueError, e: return exc.HTTPBadRequest( "Invalid value for debugcount (%r): %s" % (debugcount, e)) if debugcount not in self.debug_infos: return exc.HTTPServerError( "Debug %s not found (maybe it has expired, or the server was restarted)" % debugcount) req.debug_info = self.debug_infos[debugcount] return func(self, req) debug_info_replacement.exposed = True return debug_info_replacement debug_counter = itertools.count(int(time.time())) def get_debug_count(req): """ Return the unique debug count for the current request """ if hasattr(req, 'environ'): environ = req.environ else: environ = req # XXX: Legacy support for Paste restorer if 'paste.evalexception.debug_count' in environ: return environ['paste.evalexception.debug_count'] elif 'weberror.evalexception.debug_count' in environ: return environ['weberror.evalexception.debug_count'] else: next = debug_counter.next() environ['weberror.evalexception.debug_count'] = next environ['paste.evalexception.debug_count'] = next return next class InvalidTemplate(Exception): pass class EvalException(object): """Handles capturing an exception and turning it into an interactive exception explorer""" def __init__(self, application, global_conf=None, error_template_filename=None, xmlhttp_key=None, media_paths=None, templating_formatters=None, head_html='', footer_html='', reporters=None, libraries=None, **params): self.libraries = libraries or [] self.application = application self.debug_infos = {} self.templating_formatters = templating_formatters or [] self.head_html = HTMLTemplate(head_html) self.footer_html = HTMLTemplate(footer_html) if error_template_filename is None: error_template_filename = resource_filename( "weberror", "eval_template.html" ) if xmlhttp_key is None: if global_conf is None: xmlhttp_key = '_' else: xmlhttp_key = global_conf.get('xmlhttp_key', '_') self.xmlhttp_key = xmlhttp_key self.media_paths = media_paths or {} self.error_template = HTMLTemplate.from_filename(error_template_filename) if reporters is None: reporters = [] self.reporters = reporters def __call__(self, environ, start_response): ## FIXME: print better error message (maybe fall back on ## normal middleware, plus an error message) assert not environ['wsgi.multiprocess'], ( "The EvalException middleware is not usable in a " "multi-process environment") # XXX: Legacy support for Paste restorer environ['weberror.evalexception'] = environ['paste.evalexception'] = \ self req = Request(environ) if req.path_info_peek() == '_debug': return self.debug(req)(environ, start_response) else: return self.respond(environ, start_response) def debug(self, req): assert req.path_info_pop() == '_debug' next_part = req.path_info_pop() method = getattr(self, next_part, None) if method is None: return exc.HTTPNotFound('Nothing could be found to match %r' % next_part) if not getattr(method, 'exposed', False): return exc.HTTPForbidden('Access to %r is forbidden' % next_part) return method(req) def relay(self, req): """Relay a request to a remote machine for JS proxying""" host = req.GET['host'] conn = httplib.HTTPConnection(host) headers = req.headers # Re-assemble the query string query_str = {} for param, val in req.GET.iteritems(): if param in ['host', 'path']: continue query_str[param] = val query_str = urllib.urlencode(query_str) # Transport a GET or a POST if req.method == 'GET': conn.request("GET", '%s?%s' % (req.GET['path'], query_str), headers=headers) elif req.method == 'POST': conn.request("POST", req.GET['path'], req.body, headers=headers) # Handle the response and pull out the headers to proxy back resp = conn.getresponse() res = Response() for header, value in resp.getheaders(): if header.lower() in ['server', 'date']: continue res.headers[header] = value res.body = resp.read() return res relay.exposed=True def post_traceback(self, req): """Post the long XML traceback to the host and path provided""" debug_info = req.debug_info long_xml_er = formatter.format_xml(debug_info.exc_data, show_hidden_frames=True, show_extra_data=False, libraries=self.libraries)[0] host = req.GET['host'] headers = req.headers conn = httplib.HTTPConnection(host) headers = {'Content-Length':len(long_xml_er), 'Content-Type':'application/xml'} conn.request("POST", req.GET['path'], long_xml_er, headers=headers) resp = conn.getresponse() res = Response() for header, value in resp.getheaders(): if header.lower() in ['server', 'date']: continue res.headers[header] = value res.body = resp.read() return res post_traceback = get_debug_info(post_traceback) def media(self, req): """Static path where images and other files live""" first_part = req.path_info_peek() if first_part in self.media_paths: req.path_info_pop() path = self.media_paths[first_part] else: path = resource_filename("weberror", "eval-media") app = urlparser.StaticURLParser(path) return app media.exposed = True def summary(self, req): """ Returns a JSON-format summary of all the cached exception reports """ res = Response(content_type='text/x-json') data = []; items = self.debug_infos.values() items.sort(lambda a, b: cmp(a.created, b.created)) data = [item.json() for item in items] res.body = repr(data) return res summary.exposed = True def view(self, req): """ View old exception reports """ id = int(req.path_info_pop()) if id not in self.debug_infos: return exc.HTTPServerError( "Traceback by id %s does not exist (maybe " "the server has been restarted?)" % id) debug_info = self.debug_infos[id] return debug_info.wsgi_application view.exposed = True def make_view_url(self, environ, base_path, count): return base_path + '/view/%s' % count #@get_debug_info def show_frame(self, req): tbid = int(req.params['tbid']) frame = req.debug_info.frame(tbid) vars = frame.tb_frame.f_locals if vars: registry.restorer.restoration_begin(req.debug_info.counter) try: local_vars = make_table(vars) finally: registry.restorer.restoration_end() else: local_vars = 'No local vars' res = Response(content_type='text/html') res.body = input_form.substitute(tbid=tbid, debug_info=req.debug_info) + local_vars return res show_frame = get_debug_info(show_frame) #@get_debug_info def exec_input(self, req): input = req.params.get('input') if not input.strip(): return '' input = input.rstrip() + '\n' frame = req.debug_info.frame(int(req.params['tbid'])) vars = frame.tb_frame.f_locals glob_vars = frame.tb_frame.f_globals context = evalcontext.EvalContext(vars, glob_vars) registry.restorer.restoration_begin(req.debug_info.counter) try: output = context.exec_expr(input) finally: registry.restorer.restoration_end() input_html = formatter.str2html(input) res = Response(content_type='text/html') res.write( '
>>>
'
'%s\n%s' % (preserve_whitespace(input_html, quote=False), preserve_whitespace(output))) return res exec_input = get_debug_info(exec_input) def source_code(self, req): location = req.params['location'] module_name, lineno = location.split(':', 1) module = sys.modules.get(module_name) if module is None: # Something weird indeed res = Response(content_type='text/html', charset='utf8') res.body = 'The module
%s
does not have an entry in sys.modules' % module_name
return res
filename = module.__file__
if filename[-4:] in ('.pyc', '.pyo'):
filename = filename[:-1]
elif filename.endswith('$py.class'):
filename = '%s.py' % filename[:-9]
f = open(filename, 'rb')
source = f.read()
f.close()
html = (
(''*(60-source_lines) res = Response(content_type='text/html', charset='utf8') res.unicode_body = html return res source_code.exposed = True def respond(self, environ, start_response): req = Request(environ) if req.environ.get('paste.throw_errors'): return self.application(environ, start_response) base_path = req.application_url + '/_debug' req.environ['paste.throw_errors'] = True started = [] def detect_start_response(status, headers, exc_info=None): try: return start_response(status, headers, exc_info) except: raise else: started.append(True) try: __traceback_supplement__ = errormiddleware.Supplement, self, environ app_iter = self.application(environ, detect_start_response) # Don't create a list from a paste.fileapp object if isinstance(app_iter, fileapp._FileIter): return app_iter try: return_iter = list(app_iter) return return_iter finally: if hasattr(app_iter, 'close'): app_iter.close() except: exc_info = sys.exc_info() # Tell the Registry to save its StackedObjectProxies current state # for later restoration ## FIXME: needs to be more abstract (something in the environ) ## to remove the Paste dependency registry.restorer.save_registry_state(environ) count = get_debug_count(environ) view_uri = self.make_view_url(environ, base_path, count) if not started: headers = [('content-type', 'text/html')] headers.append(('X-Debug-URL', view_uri)) start_response('500 Internal Server Error', headers, exc_info) environ['wsgi.errors'].write('Debug at: %s\n' % view_uri) exc_data = collector.collect_exception(*exc_info) exc_data.view_url = view_uri if self.reporters: for reporter in self.reporters: reporter.report(exc_data) debug_info = DebugInfo(count, exc_info, exc_data, base_path, environ, view_uri, self.error_template, self.templating_formatters, self.head_html, self.footer_html, self.libraries) assert count not in self.debug_infos self.debug_infos[count] = debug_info if self.xmlhttp_key: if self.xmlhttp_key in req.params: exc_data = collector.collect_exception(*exc_info) html, extra_html = formatter.format_html( exc_data, include_hidden_frames=False, include_reusable=False, show_extra_data=False) return [html, extra_html] # @@: it would be nice to deal with bad content types here return debug_info.content() class DebugInfo(object): def __init__(self, counter, exc_info, exc_data, base_path, environ, view_uri, error_template, templating_formatters, head_html, footer_html, libraries): self.counter = counter self.exc_data = exc_data self.base_path = base_path self.environ = environ self.view_uri = view_uri self.error_template = error_template self.created = time.time() self.templating_formatters = templating_formatters self.head_html = head_html self.footer_html = footer_html self.libraries = libraries self.exc_type, self.exc_value, self.tb = exc_info __exception_formatter__ = 1 self.frames = [] n = 0 tb = self.tb while tb is not None and (limit is None or n < limit): if tb.tb_frame.f_locals.get('__exception_formatter__'): # Stop recursion. @@: should make a fake ExceptionFrame break self.frames.append(tb) tb = tb.tb_next n += 1 def json(self): """Return the JSON-able representation of this object""" return { 'uri': self.view_uri, 'created': time.strftime('%c', time.gmtime(self.created)), 'created_timestamp': self.created, 'exception_type': str(self.exc_type), 'exception': str(self.exc_value), } def frame(self, tbid): for frame in self.frames: if id(frame) == tbid: return frame else: raise ValueError, ( "No frame by id %s found from %r" % (tbid, self.frames)) def wsgi_application(self, environ, start_response): start_response('200 OK', [('content-type', 'text/html')]) return self.content() def content(self): traceback_body, extra_data = format_eval_html(self.exc_data, self.base_path, self.counter, self.libraries) repost_button = make_repost_button(self.environ) template_data = '
No Template information available.
' tab = 'traceback_data' for tmpl_formatter in self.templating_formatters: result = tmpl_formatter(self.exc_value) if result: tab = 'template_data' template_data = result break # Decode the exception value itself if needed formatted_exc_value = self.exc_data.exception_value if isinstance(formatted_exc_value, str): last_frame = self.exc_data.frames[-1] formatted_exc_value = formatted_exc_value.decode(last_frame.source_encoding, 'replace') formatted_exc_value = formatted_exc_value.encode('latin1', 'htmlentityreplace') formatted_exc_value = html_quote(formatted_exc_value) template_data = template_data.replace('', '')
template_data = template_data.replace('
', '')
if hasattr(self.exc_data.exception_type, '__name__'):
exc_name = self.exc_data.exception_type.__name__
else:
exc_name = str(self.exc_data.exception_type)
page = self.error_template.substitute(
head_html=self.head_html.substitute(prefix=self.base_path),
pygments_css=formatter.pygments_css,
footer_html=self.footer_html.substitute(prefix=self.base_path),
repost_button=repost_button or '',
traceback_body=traceback_body,
exc_data=self.exc_data,
exc_name=exc_name,
formatted_exc_value=formatted_exc_value,
extra_data=extra_data,
template_data=template_data,
set_tab=tab,
prefix=self.base_path,
counter=self.counter,
)
return [page]
class EvalHTMLFormatter(formatter.HTMLFormatter):
def __init__(self, base_path, counter, **kw):
super(EvalHTMLFormatter, self).__init__(**kw)
self.base_path = base_path
self.counter = counter
def format_source_line(self, filename, frame):
line = formatter.HTMLFormatter.format_source_line(
self, filename, frame)
location = '%s:%s' % (frame.modname, frame.lineno)
return (line +
' '
'
{{name}} | {{preserve_whitespace(value_html, quote=False)|html}}{{if expand_html}} ... {{endif}} |
' % url) else: # @@: I'd like to reconstruct this, but I can't because # the POST body is probably lost at this point, and # I can't get it back :( return None # @@: Use or lose the following code block """ fields = [] for name, value in request.parse_formvars( environ, include_get_vars=False).items(): if hasattr(value, 'filename'): # @@: Arg, we'll just submit the body, and leave out # the filename :( value = value.value fields.append( '' % (html_quote(name), html_quote(value))) return ''' ''' % (url, '\n'.join(fields)) """ input_form = HTMLTemplate(''' ''', name='input_form') def make_eval_exception(app, global_conf, xmlhttp_key=None, reporters=None): """ Wraps the application in an interactive debugger. This debugger is a major security hole, and should only be used during development. xmlhttp_key is a string that, if present in QUERY_STRING, indicates that the request is an XMLHttp request, and the Javascript/interactive debugger should not be returned. (If you try to put the debugger somewhere with innerHTML, you will often crash the browser) """ if xmlhttp_key is None: xmlhttp_key = global_conf.get('xmlhttp_key', '_') if reporters is None: reporters = global_conf.get('error_reporters') if reporters and isinstance(reporters, basestring): reporter_strings = reporters.split() reporters = [] for reporter_string in reporter_strings: reporter = import_string.eval_import(reporter_string) if isinstance(reporter, (type, types.ClassType)): reporter = reporter() reporters.append(reporter) return EvalException(app, xmlhttp_key=xmlhttp_key, reporters=reporters) def make_general_exception(app, global_conf, interactive=False, **kw): """ Creates an error-catching middleware. If `interactive` is true then it will be the interactive exception catcher, otherwise it will be the static exception catcher. """ from paste.deploy.converters import asbool interactive = asbool(interactive) if interactive: return make_eval_exception(app, global_conf, **kw) else: from weberror.errormiddleware import make_error_middleware return make_error_middleware(app, global_conf, **kw) WebError-0.10.3/weberror/exceptions/ 000775 000765 000024 00000000000 11466345335 017255 5 ustar 00ben staff 000000 000000 WebError-0.10.3/weberror/formatter.py 000664 000765 000024 00000065151 11335430006 017442 0 ustar 00ben staff 000000 000000 # (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org) # Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php """ Formatters for the exception data that comes from ExceptionCollector. """ # @@: TODO: # Use this: http://www.zope.org/Members/tino/VisualTraceback/VisualTracebackNews import cgi import re import sys from weberror.util import escaping from xml.dom.minidom import getDOMImplementation from pygments import highlight as pygments_highlight from pygments.lexers import ClassNotFound, PythonLexer, TextLexer, \ get_lexer_for_filename from pygments.formatters import HtmlFormatter try: import pkg_resources except ImportError: pkg_resources = None def html_quote(s): return cgi.escape(str(s), True) pygments_css = HtmlFormatter().get_style_defs('.highlight') def highlight(filename, code, linenos=False, lineanchors=None, cssclass='highlight'): if lineanchors is None and linenos: lineanchors = 'code' lexer = None if filename: if filename.endswith('.py'): # XXX: Pygments gives back NumPyLexer for some reason, which # we don't need lexer = PythonLexer() else: try: lexer = get_lexer_for_filename(filename) except ClassNotFound: pass if not lexer: lexer = TextLexer() formatter = HtmlFormatter(linenos=linenos, lineanchors=lineanchors, cssclass=cssclass) return pygments_highlight(code, lexer, formatter) class AbstractFormatter(object): general_data_order = ['object', 'source_url'] def __init__(self, show_hidden_frames=False, include_reusable=True, show_extra_data=True, trim_source_paths=(), **kwargs): self.show_hidden_frames = show_hidden_frames self.trim_source_paths = trim_source_paths self.include_reusable = include_reusable self.show_extra_data = show_extra_data self.extra_kwargs = kwargs def format_collected_data(self, exc_data): general_data = {} if self.show_extra_data: for name, value_list in exc_data.extra_data.items(): if isinstance(name, tuple): importance, title = name else: importance, title = 'normal', name for value in value_list: general_data[(importance, name)] = self.format_extra_data( importance, title, value) lines = [] frames = self.filter_frames(exc_data.frames) for frame in frames: self.frame = frame res = self.format_frame_start(frame) if res: lines.append(res) sup = frame.supplement if sup: if sup.object: general_data[('important', 'object')] = self.format_sup_object( sup.object) if sup.source_url: general_data[('important', 'source_url')] = self.format_sup_url( sup.source_url) if sup.line: lines.append(self.format_sup_line_pos(sup.line, sup.column)) if sup.expression: lines.append(self.format_sup_expression(sup.expression)) if sup.warnings: for warning in sup.warnings: lines.append(self.format_sup_warning(warning)) if sup.info: lines.extend(self.format_sup_info(sup.info)) if frame.supplement_exception: lines.append('Exception in supplement:') lines.append(self.quote_long(frame.supplement_exception)) if frame.traceback_info: lines.append(self.format_traceback_info(frame.traceback_info)) filename = frame.filename if filename and self.trim_source_paths: for path, repl in self.trim_source_paths: if filename.startswith(path): filename = repl + filename[len(path):] break lines.append(self.format_source_line(filename or '?', frame)) source = frame.get_source_line() long_source = frame.get_source_line(2) if source: lines.append(self.format_long_source(filename, source, long_source)) res = self.format_frame_end(frame) if res: lines.append(res) etype = exc_data.exception_type if not isinstance(etype, basestring): etype = etype.__name__ exc_info = self.format_exception_info( etype, exc_data.exception_value) data_by_importance = {'important': [], 'normal': [], 'supplemental': [], 'extra': []} for (importance, name), value in general_data.items(): data_by_importance[importance].append( (name, value)) for value in data_by_importance.values(): value.sort() return self.format_combine(data_by_importance, lines, exc_info) def filter_frames(self, frames): """ Removes any frames that should be hidden, according to the values of traceback_hide, self.show_hidden_frames, and the hidden status of the final frame. """ if self.show_hidden_frames: return frames new_frames = [] hidden = False for frame in frames: hide = frame.traceback_hide # @@: It would be nice to signal a warning if an unknown # hide string was used, but I'm not sure where to put # that warning. if hide == 'before': new_frames = [] hidden = False elif hide == 'before_and_this': new_frames = [] hidden = False continue elif hide == 'reset': hidden = False elif hide == 'reset_and_this': hidden = False continue elif hide == 'after': hidden = True elif hide == 'after_and_this': hidden = True continue elif hide: continue elif hidden: continue new_frames.append(frame) if frames[-1] not in new_frames: # We must include the last frame; that we don't indicates # that the error happened where something was "hidden", # so we just have to show everything return frames return new_frames def format_frame_start(self, frame): """ Called before each frame starts; may return None to output no text. """ return None def format_frame_end(self, frame): """ Called after each frame ends; may return None to output no text. """ return None def pretty_string_repr(self, s): """ Formats the string as a triple-quoted string when it contains newlines. """ if '\n' in s: s = repr(s) s = s[0]*3 + s[1:-1] + s[-1]*3 s = s.replace('\\n', '\n') return s else: return repr(s) def long_item_list(self, lst): """ Returns true if the list contains items that are long, and should be more nicely formatted. """ how_many = 0 for item in lst: if len(repr(item)) > 40: how_many += 1 if how_many >= 3: return True return False class TextFormatter(AbstractFormatter): def quote(self, s): if isinstance(s, str) and hasattr(self, 'frame'): s = s.decode(self.frame.source_encoding, 'replace') return s.encode('latin1', 'htmlentityreplace') def quote_long(self, s): return self.quote(s) def emphasize(self, s): return s def format_sup_object(self, obj): return 'In object: %s' % self.emphasize(self.quote(repr(obj))) def format_sup_url(self, url): return 'URL: %s' % self.quote(url) def format_sup_line_pos(self, line, column): if column: return self.emphasize('Line %i, Column %i' % (line, column)) else: return self.emphasize('Line %i' % line) def format_sup_expression(self, expr): return self.emphasize('In expression: %s' % self.quote(expr)) def format_sup_warning(self, warning): return 'Warning: %s' % self.quote(warning) def format_sup_info(self, info): return [self.quote_long(info)] def format_source_line(self, filename, frame): return 'File %r, line %s in %s' % ( filename, frame.lineno or '?', frame.name or '?') def format_long_source(self, filename, source, long_source): return self.format_source(filename, source) def format_source(self, filename, source_line): return ' ' + self.quote(source_line.strip()) def format_exception_info(self, etype, evalue): return self.emphasize( '%s: %s' % (self.quote(etype), self.quote(evalue))) def format_traceback_info(self, info): return info def format_combine(self, data_by_importance, lines, exc_info): lines[:0] = [value for n, value in data_by_importance['important']] lines.append(exc_info) for name in 'normal', 'supplemental', 'extra': lines.extend([value for n, value in data_by_importance[name]]) return self.format_combine_lines(lines), '' def format_combine_lines(self, lines): return '\n'.join([convert_to_str(line) for line in lines]) def format_extra_data(self, importance, title, value): if isinstance(value, str): s = self.pretty_string_repr(value) if '\n' in s: return '%s:\n%s' % (title, s) else: return '%s: %s' % (title, s) elif isinstance(value, dict): lines = ['\n', title, '-'*len(title)] items = value.items() items.sort() for n, v in items: try: v = repr(v) except Exception, e: v = 'Cannot display: %s' % e v = truncate(v) lines.append(' %s: %s' % (n, v)) return '\n'.join(lines) elif (isinstance(value, (list, tuple)) and self.long_item_list(value)): parts = [truncate(repr(v)) for v in value] return '%s: [\n %s]' % ( title, ',\n '.join(parts)) else: return '%s: %s' % (title, truncate(repr(value))) class HTMLFormatter(TextFormatter): def quote(self, s): if isinstance(s, str) and hasattr(self, 'frame'): s = s.decode(self.frame.source_encoding, 'replace') s = s.encode('latin1', 'htmlentityreplace') return html_quote(s) def quote_long(self, s): return '
%s' % self.quote(s) def emphasize(self, s): return '%s' % s def format_sup_url(self, url): return 'URL: %s' % (url, url) def format_combine_lines(self, lines): ## FIXME: this is horrible: new_lines = [] for line in lines: if not line.startswith('
' new_lines.append(convert_to_str(line)) return '\n'.join(new_lines) def format_source_line(self, filename, frame): self.frame = frame name = self.quote(frame.name or '?') return 'Module %s:%s in
%s
' % (
filename, frame.modname or '?', frame.lineno or '?',
name)
def format_long_source(self, filename, source, long_source):
q_long_source = str2html(long_source, False, 4, True, getattr(self, 'frame', None),
filename=filename)
q_source = str2html(source, True, 0, False, getattr(self, 'frame', None),
filename=filename)
return (' '
'%s
' % self.quote(source_line.strip())
def format_traceback_info(self, info):
return '%s' % self.quote(info) def format_frame_start(self, frame): ## FIXME: make it zebra? return '
%s' % (title, self.quote(s)) else: return '%s: %s' % (title, self.quote(s)) elif isinstance(value, dict): return self.zebra_table(title, value) elif (isinstance(value, (list, tuple)) and self.long_item_list(value)): return '%s: [
\n %s]' % ( title, ',
'.join(map(self.quote, map(repr, value)))) else: return '%s: %s' % (title, self.quote(repr(value))) def format_combine(self, data_by_importance, lines, exc_info): lines[:0] = [value for n, value in data_by_importance['important']] lines.append(exc_info) for name in 'normal', 'supplemental': lines.extend([value for n, value in data_by_importance[name]]) extra_data = [] if data_by_importance['extra']: extra_data.extend([value for n, value in data_by_importance['extra']]) text = self.format_combine_lines(lines) ## FIXME: something about this is wrong: if self.include_reusable: return text, extra_data else: # Usually because another error is already on this page, # and so the js & CSS are unneeded return text, extra_data def zebra_table(self, title, rows, table_class="variables"): if isinstance(rows, dict): rows = rows.items() rows.sort() table = ['
%s | |
---|---|
%s | ' % (odd and 'odd' or 'even', self.quote(name))) table.append( '%s |
ERROR: .*?
') def str2html(src, strip=False, indent_subsequent=0, highlight_inner=False, frame=None, filename=None): """ Convert a string to HTML. Try to be really safe about it, returning a quoted version of the string if nothing else works. """ try: return _str2html(src, strip=strip, indent_subsequent=indent_subsequent, highlight_inner=highlight_inner, frame=frame, filename=filename) except: if isinstance(src, str) and frame: src = src.decode(frame.source_encoding, 'replace') src = src.encode('latin1', 'htmlentityreplace') return src return html_quote(src) def _str2html(src, strip=False, indent_subsequent=0, highlight_inner=False, frame=None, filename=None): if strip: src = src.strip() orig_src = src try: src = highlight(filename, src) src = error_re.sub('', src) src = pre_re.sub('', src) src = re.sub(r'^[\n\r]{0,1}', '', src) src = re.sub(r'[\n\r]{0,1}$', '', src) # This gets rid of the\n'.join(lines) src = whitespace_re.sub( lambda m: ' '*(len(m.group(0))-1) + ' ', src) return src def truncate(string, limit=1000): """ Truncate the string to the limit number of characters """ if len(string) > limit: return string[:limit-20]+'...'+string[-17:] else: return string def make_wrappable(html, wrap_limit=60, split_on=';?&@!$#-/\\"\''): # Currently using
`` block, so wrap on a line-by-line basis. """ lines = html.splitlines() new_lines = [] for line in lines: if len(line) > wrap_limit: for char in split_on: if char in line: parts = line.split(char) line = ''.join(parts) break new_lines.append(line) return '\n'.join(lines) def convert_to_str(s): if isinstance(s, unicode): return s.encode('utf8') return s WebError-0.10.3/weberror/pdbcapture.py 000664 000765 000024 00000011616 11466344257 017606 0 ustar 00ben staff 000000 000000 from webob import Request, Response import threading from paste.util import threadedprint from itertools import count import tempita from paste.urlparser import StaticURLParser from paste.util.filemixin import FileMixin import os import sys try: import json except ImportError: # pragma: no cover import simplejson as json here = os.path.dirname(os.path.abspath(__file__)) #def debug(msg, *args): # args = '%s %s' % (msg, ' '.join(map(repr, args))) # print >> sys.stderr, args class PdbCapture(object): def __init__(self, app): self.app = app threadedprint.install(leave_stdout=True) threadedprint.install_stdin() self.counter = count() self.static_app = StaticURLParser(os.path.join(here, 'pdbcapture/static')) self.media_app = StaticURLParser(os.path.join(here, 'eval-media')) self.states = {} def get_template(self, template_name): filename = os.path.join(os.path.dirname(__file__), template_name) return tempita.HTMLTemplate.from_filename(filename) def __call__(self, environ, start_response): req = Request(environ) if req.GET.get('__pdbid__'): id = int(req.GET['__pdbid__']) response = self.states[id]['response'] return response(environ, start_response) if req.path_info_peek() == '.pdbcapture': req.path_info_pop() if req.path_info_peek() == 'static': req.path_info_pop() return self.static_app(environ, start_response) if req.path_info_peek() == 'media': req.path_info_pop() return self.media_app(environ, start_response) resp = self.internal_request(req) return resp(environ, start_response) id = self.counter.next() state = dict(id=id, event=threading.Event(), base_url=req.application_url, stdout=[], stdin=[], stdin_event=threading.Event()) t = threading.Thread(target=self.call_app, args=(req, state)) t.setDaemon(True) t.start() state['event'].wait() if 'response' in state: # Normal request, nothing happened resp = state['response'] return resp(environ, start_response) if 'exc_info' in state: raise state['exc_info'][0], state['exc_info'][1], state['exc_info'][2] self.states[id] = state tmpl = self.get_template('pdbcapture_response.html') body = tmpl.substitute(req=req, state=state, id=id) resp = Response(body) return resp(environ, start_response) def internal_request(self, req): id = int(req.params['id']) state = self.states[id] if 'response' in state: body = {'response': 1} else: if req.params.get('stdin'): state['stdin'].append(req.params['stdin']) state['stdin_event'].set() stdout = ''.join(state['stdout']) state['stdout'][:] = [] body = {'stdout': stdout} if not state['stdin_event'].isSet(): body['stdinPending'] = 1 resp = Response(content_type='application/json', body=json.dumps(body)) return resp def call_app(self, req, state): event = state['event'] stream_handler = StreamHandler(stdin=state['stdin'], stdin_event=state['stdin_event'], stdout=state['stdout'], signal_event=state['event']) threadedprint.register(stream_handler) threadedprint.register_stdin(stream_handler) try: resp = req.get_response(self.app) state['response'] = resp except: state['exc_info'] = sys.exc_info() event.set() class StreamHandler(FileMixin): def __init__(self, stdin, stdout, stdin_event, signal_event): self.stdin = stdin self.stdout = stdout self.stdin_event = stdin_event self.signal_event = signal_event def write(self, text): self.stdout.append(text) def read(self, size=None): self.signal_event.set() text = ''.join(self.stdin) if size is None or size == -1: self.stdin[:] = [] sys.stdout.write(text) return text while len(text) < size: self.stdin_event.clear() self.stdin_event.wait() text = ''.join(self.stdin) pending = text[:size] self.stdin[:] = [text[size:]] sys.stdout.write(pending) return pending def test_app(environ, start_response): import pdb message = "Hey, what's up?" pdb.set_trace() start_response('200 OK', [('Content-type', 'text/plain')]) return [message] if __name__ == '__main__': from paste import httpserver httpserver.serve(PdbCapture(test_app)) WebError-0.10.3/weberror/reporter.py 000664 000765 000024 00000011531 11335430006 017272 0 ustar 00ben staff 000000 000000 # (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org) # Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php from email.MIMEText import MIMEText from email.MIMEMultipart import MIMEMultipart import smtplib import time from weberror import formatter class Reporter(object): def __init__(self, **conf): for name, value in conf.items(): if not hasattr(self, name): raise TypeError( "The keyword argument %s was not expected" % name) setattr(self, name, value) self.check_params() def check_params(self): pass def format_date(self, exc_data): return time.strftime('%c', exc_data.date) def format_html(self, exc_data, **kw): return formatter.format_html(exc_data, **kw) def format_text(self, exc_data, **kw): return formatter.format_text(exc_data, **kw) class EmailReporter(Reporter): to_addresses = None from_address = None smtp_server = 'localhost' smtp_username = None smtp_password = None smtp_use_tls = False subject_prefix = '' def report(self, exc_data): msg = self.assemble_email(exc_data) server = smtplib.SMTP(self.smtp_server) if self.smtp_use_tls: server.ehlo() server.starttls() server.ehlo() if self.smtp_username and self.smtp_password: server.login(self.smtp_username, self.smtp_password) ## FIXME: this should check the return value from this function: result = server.sendmail(self.from_address, self.to_addresses, msg.as_string()) try: server.quit() except sslerror: # sslerror is raised in tls connections on closing sometimes pass def check_params(self): if not self.to_addresses: raise ValueError("You must set to_addresses") if not self.from_address: raise ValueError("You must set from_address") if isinstance(self.to_addresses, (str, unicode)): self.to_addresses = [self.to_addresses] def assemble_email(self, exc_data): short_html_version, short_extra = self.format_html( exc_data, show_hidden_frames=False, show_extra_data=True) long_html_version, long_extra = self.format_html( exc_data, show_hidden_frames=True, show_extra_data=True) text_version = self.format_text( exc_data, show_hidden_frames=True, show_extra_data=True)[0] msg = MIMEMultipart() msg.set_type('multipart/alternative') msg.preamble = msg.epilogue = '' text_msg = MIMEText(as_str(text_version)) text_msg.set_type('text/plain') text_msg.set_param('charset', 'UTF-8') msg.attach(text_msg) html_msg = MIMEText(as_str(short_html_version) + as_str(''.join(short_extra))) html_msg.set_type('text/html') html_msg.set_param('charset', 'UTF-8') html_long = MIMEText(as_str(long_html_version) + as_str(''.join(long_extra))) html_long.set_type('text/html') html_long.set_param('charset', 'UTF-8') msg.attach(html_msg) msg.attach(html_long) subject = as_str('%s: %s' % (exc_data.exception_type, formatter.truncate(str(exc_data.exception_value)))) msg['Subject'] = as_str(self.subject_prefix) + subject msg['From'] = as_str(self.from_address) msg['To'] = as_str(', '.join(self.to_addresses)) return msg class LogReporter(Reporter): filename = None show_hidden_frames = True def check_params(self): assert self.filename is not None, ( "You must give a filename") def report(self, exc_data): text, head_text = self.format_text( exc_data, show_hidden_frames=self.show_hidden_frames) f = open(self.filename, 'a') try: f.write(text + '\n' + '-'*60 + '\n') finally: f.close() class FileReporter(Reporter): file = None show_hidden_frames = True def check_params(self): assert self.file is not None, ( "You must give a file object") def report(self, exc_data): text = self.format_text( exc_data, show_hidden_frames=self.show_hidden_frames) self.file.write(text + '\n' + '-'*60 + '\n') class WSGIAppReporter(Reporter): def __init__(self, exc_data): self.exc_data = exc_data def __call__(self, environ, start_response): start_response('500 Server Error', [('Content-type', 'text/html')]) return [formatter.format_html(self.exc_data)] def as_str(v): if isinstance(v, str): return v if not isinstance(v, unicode): v = unicode(v) if isinstance(v, unicode): v = v.encode('utf8') return v WebError-0.10.3/weberror/util/ 000775 000765 000024 00000000000 11466345335 016051 5 ustar 00ben staff 000000 000000 WebError-0.10.3/weberror/util/__init__.py 000600 000765 000024 00000000000 10723213331 020117 0 ustar 00ben staff 000000 000000 WebError-0.10.3/weberror/util/errorapp.py 000644 000765 000024 00000000462 10727022360 020242 0 ustar 00ben staff 000000 000000 """ This simple application creates errors """ def error_app(environ, start_response): environ['errorapp.item'] = 1 raise_error() def raise_error(): if 1 == 1: raise Exception('This is an exception') else: do_stuff() def make_error_app(global_conf): return error_app WebError-0.10.3/weberror/util/escaping.py 000664 000765 000024 00000017123 11016722455 020211 0 ustar 00ben staff 000000 000000 # filters.py # Copyright (C) 2006, 2007, 2008 Geoffrey T. Dairiki # and Michael Bayer and Ben Bangert # # This module heavily based on the one from Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php import re, cgi, urllib, htmlentitydefs, codecs from StringIO import StringIO xml_escapes = { '&' : '&', '>' : '>', '<' : '<', '"' : '"', # also " in html-only "'" : ''' # also ' in html-only } # XXX: " is valid in HTML and XML # ' is not valid HTML, but is valid XML def html_escape(string): return cgi.escape(string, True) def xml_escape(string): return re.sub(r'([&<"\'>])', lambda m: xml_escapes[m.group()], string) def url_escape(string): # convert into a list of octets string = string.encode("utf8") return urllib.quote_plus(string) def url_unescape(string): text = urllib.unquote_plus(string) if not is_ascii_str(text): text = text.decode("utf8") return text def trim(string): return string.strip() class Decode(object): def __getattr__(self, key): def decode(x): if isinstance(x, unicode): return x elif not isinstance(x, str): return unicode(str(x), encoding=key) else: return unicode(x, encoding=key) return decode decode = Decode() _ASCII_re = re.compile(r'\A[\x00-\x7f]*\Z') def is_ascii_str(text): return isinstance(text, str) and _ASCII_re.match(text) ################################################################ class XMLEntityEscaper(object): def __init__(self, codepoint2name, name2codepoint): self.codepoint2entity = dict([(c, u'&%s;' % n) for c,n in codepoint2name.iteritems()]) self.name2codepoint = name2codepoint def escape_entities(self, text): """Replace characters with their character entity references. Only characters corresponding to a named entity are replaced. """ return unicode(text).translate(self.codepoint2entity) def __escape(self, m): codepoint = ord(m.group()) try: return self.codepoint2entity[codepoint] except (KeyError, IndexError): return '%X;' % codepoint __escapable = re.compile(r'["&<>]|[^\x00-\x7f]') def escape(self, text): """Replace characters with their character references. Replace characters by their named entity references. Non-ASCII characters, if they do not have a named entity reference, are replaced by numerical character references. The return value is guaranteed to be ASCII. """ return self.__escapable.sub(self.__escape, unicode(text) ).encode('ascii') # XXX: This regexp will not match all valid XML entity names__. # (It punts on details involving involving CombiningChars and Extenders.) # # .. __: http://www.w3.org/TR/2000/REC-xml-20001006#NT-EntityRef __characterrefs = re.compile(r'''& (?: \#(\d+) | \#x([\da-f]+) | ( (?!\d) [:\w] [-.:\w]+ ) ) ;''', re.X | re.UNICODE) def __unescape(self, m): dval, hval, name = m.groups() if dval: codepoint = int(dval) elif hval: codepoint = int(hval, 16) else: codepoint = self.name2codepoint.get(name, 0xfffd) # U+FFFD = "REPLACEMENT CHARACTER" if codepoint < 128: return chr(codepoint) return unichr(codepoint) def unescape(self, text): """Unescape character references. All character references (both entity references and numerical character references) are unescaped. """ return self.__characterrefs.sub(self.__unescape, text) _html_entities_escaper = XMLEntityEscaper(htmlentitydefs.codepoint2name, htmlentitydefs.name2codepoint) html_entities_escape = _html_entities_escaper.escape_entities html_entities_unescape = _html_entities_escaper.unescape def htmlentityreplace_errors(ex): """An encoding error handler. This python `codecs`_ error handler replaces unencodable characters with HTML entities, or, if no HTML entity exists for the character, XML character references. >>> u'The cost was \u20ac12.'.encode('latin1', 'htmlentityreplace') 'The cost was €12.' """ if isinstance(ex, UnicodeEncodeError): # Handle encoding errors bad_text = ex.object[ex.start:ex.end] text = _html_entities_escaper.escape(bad_text) return (unicode(text), ex.end) raise ex codecs.register_error('htmlentityreplace', htmlentityreplace_errors) # TODO: options to make this dynamic per-compilation will be added in a later release DEFAULT_ESCAPES = { 'x':'filters.xml_escape', 'h':'filters.html_escape', 'u':'filters.url_escape', 'trim':'filters.trim', 'entity':'filters.html_entities_escape', 'unicode':'unicode', 'decode':'decode', 'str':'str', 'n':'n' } # regexps used by _translateCdata(), # made global to compile once. # see http://www.xml.com/axml/target.html#dt-character ILLEGAL_LOW_CHARS = '[\x01-\x08\x0B-\x0C\x0E-\x1F]' ILLEGAL_HIGH_CHARS = '\xEF\xBF[\xBE\xBF]' # Note: Prolly fuzzy on this, but it looks as if characters from the # surrogate block are allowed if in scalar form, which is encoded in UTF8 the # same was as in surrogate block form XML_ILLEGAL_CHAR_PATTERN = re.compile( '%s|%s' % (ILLEGAL_LOW_CHARS, ILLEGAL_HIGH_CHARS)) # the characters that we will want to turn into entrefs # We must do so for &, <, and > following ]]. # The xml parser has more leeway, but we're not the parser. # http://www.xml.com/axml/target.html#dt-chardata # characters that we must *always* turn to entrefs: g_cdataCharPatternReq = re.compile('[&<]|]]>') g_charToEntityReq = { '&': '&', '<': '<', ']]>': ']]>', } # characters that we must turn to entrefs in attr values: g_cdataCharPattern = re.compile('[&<>"\']|]]>') g_charToEntity = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', ']]>': ']]>', } def removeIllegalChars(characters): if XML_ILLEGAL_CHAR_PATTERN.search(characters): characters = XML_ILLEGAL_CHAR_PATTERN.subn( lambda m: '%i;' % ord(m.group()), characters)[0] return characters def translateCdata(characters, allEntRefs = None): """Translate characters into a legal format.""" if not characters: return '' if allEntRefs: # translate all chars to entrefs; for attr value if g_cdataCharPattern.search(characters): new_string = g_cdataCharPattern.subn( lambda m, d=g_charToEntity: d[m.group()], characters)[0] else: new_string = characters else: # translate only required chars to entrefs if g_cdataCharPatternReq.search(characters): new_string = g_cdataCharPatternReq.subn( lambda m, d=g_charToEntityReq: d[m.group()], characters)[0] else: new_string = characters if XML_ILLEGAL_CHAR_PATTERN.search(new_string): new_string = XML_ILLEGAL_CHAR_PATTERN.subn( lambda m: '%i;' % ord(m.group()), new_string)[0] return new_string WebError-0.10.3/weberror/util/serial_number_generator.py 000664 000765 000024 00000007620 11070224122 023302 0 ustar 00ben staff 000000 000000 # (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org) # Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php """ Creates a human-readable identifier, using numbers and digits, avoiding ambiguous numbers and letters. hash_identifier can be used to create compact representations that are unique for a certain string (or concatenation of strings) """ try: from hashlib import md5 except ImportError: from md5 import md5 good_characters = "23456789abcdefghjkmnpqrtuvwxyz" base = len(good_characters) def make_identifier(number): """ Encodes a number as an identifier. """ if not isinstance(number, (int, long)): raise ValueError( "You can only make identifiers out of integers (not %r)" % number) if number < 0: raise ValueError( "You cannot make identifiers out of negative numbers: %r" % number) result = [] while number: next = number % base result.append(good_characters[next]) # Note, this depends on integer rounding of results: number = number / base return ''.join(result) def hash_identifier(s, length, pad=True, hasher=md5, prefix='', group=None, upper=False): """ Hashes the string (with the given hashing module), then turns that hash into an identifier of the given length (using modulo to reduce the length of the identifier). If ``pad`` is False, then the minimum-length identifier will be used; otherwise the identifier will be padded with 0's as necessary. ``prefix`` will be added last, and does not count towards the target length. ``group`` will group the characters with ``-`` in the given lengths, and also does not count towards the target length. E.g., ``group=4`` will cause a identifier like ``a5f3-hgk3-asdf``. Grouping occurs before the prefix. """ if not callable(hasher): # Accept sha/md5 modules as well as callables hasher = hasher.new if length > 26 and hasher is md5: raise ValueError, ( "md5 cannot create hashes longer than 26 characters in " "length (you gave %s)" % length) if isinstance(s, unicode): s = s.encode('utf-8') h = hasher(str(s)) bin_hash = h.digest() modulo = base ** length number = 0 for c in list(bin_hash): number = (number * 256 + ord(c)) % modulo ident = make_identifier(number) if pad: ident = good_characters[0]*(length-len(ident)) + ident if group: parts = [] while ident: parts.insert(0, ident[-group:]) ident = ident[:-group] ident = '-'.join(parts) if upper: ident = ident.upper() return prefix + ident # doctest tests: __test__ = { 'make_identifier': """ >>> make_identifier(0) '' >>> make_identifier(1000) 'c53' >>> make_identifier(-100) Traceback (most recent call last): ... ValueError: You cannot make identifiers out of negative numbers: -100 >>> make_identifier('test') Traceback (most recent call last): ... ValueError: You can only make identifiers out of integers (not 'test') >>> make_identifier(1000000000000) 'c53x9rqh3' """, 'hash_identifier': """ >>> hash_identifier(0, 5) 'cy2dr' >>> hash_identifier(0, 10) 'cy2dr6rg46' >>> hash_identifier('this is a test of a long string', 5) 'awatu' >>> hash_identifier(0, 26) 'cy2dr6rg46cx8t4w2f3nfexzk4' >>> hash_identifier(0, 30) Traceback (most recent call last): ... ValueError: md5 cannot create hashes longer than 26 characters in length (you gave 30) >>> hash_identifier(0, 10, group=4) 'cy-2dr6-rg46' >>> hash_identifier(0, 10, group=4, upper=True, prefix='M-') 'M-CY-2DR6-RG46' """} if __name__ == '__main__': import doctest doctest.testmod() WebError-0.10.3/weberror/util/source_encoding.py 000664 000765 000024 00000003156 11010417022 021550 0 ustar 00ben staff 000000 000000 """Parse a Python source code encoding string""" import codecs import re # Regexp to match python magic encoding line PYTHON_MAGIC_COMMENT_re = re.compile( r'[ \t\f]* \# .* coding[=:][ \t]*([-\w.]+)', re.VERBOSE) def parse_encoding(lines): """Deduce the encoding of a source file from magic comment. It does this in the same way as the `Python interpreter`__ .. __: http://docs.python.org/ref/encodings.html The ``lines`` argument should be a list of the first 2 lines of the source code. (From Jeff Dairiki) """ try: line1 = lines[0] has_bom = line1.startswith(codecs.BOM_UTF8) if has_bom: line1 = line1[len(codecs.BOM_UTF8):] m = PYTHON_MAGIC_COMMENT_re.match(line1) if not m: try: import parser parser.suite(line1) except (ImportError, SyntaxError): # Either it's a real syntax error, in which case the source is # not valid python source, or line2 is a continuation of line1, # in which case we don't want to scan line2 for a magic # comment. pass else: line2 = lines[1] m = PYTHON_MAGIC_COMMENT_re.match(line2) if has_bom: if m: raise SyntaxError( "python refuses to compile code with both a UTF8 " "byte-order-mark and a magic encoding comment") return 'utf_8' elif m: return m.group(1) else: return None except: return None WebError-0.10.3/weberror/exceptions/__init__.py 000600 000765 000024 00000000002 10770066101 021330 0 ustar 00ben staff 000000 000000 # WebError-0.10.3/weberror/exceptions/errormiddleware.py 000664 000765 000024 00000001243 11003173153 022776 0 ustar 00ben staff 000000 000000 import warnings def ErrorMiddleware(*args, **kw): warnings.warn( 'weberror.exceptions.errormiddleware.ErrorMiddleware has been moved ' 'to weberror.errormiddleware.ErrorMiddleware', DeprecationWarning, stacklevel=2) from weberror.errormiddleware import ErrorMiddleware return ErrorMiddleware(*args, **kw) def handle_exception(*args, **kw): warnings.warn( 'weberror.exceptions.errormiddleware.handle_exception has been moved ' 'to weberror.errormiddleware.handle_exception', DeprecationWarning, stacklevel=2) from weberror.errormiddleware import handle_exceptions return handle_exceptions(*args, **kw) WebError-0.10.3/weberror/eval-media/debug.js 000664 000765 000024 00000025210 11126232531 020506 0 ustar 00ben staff 000000 000000 function showFrame(anchor) { var tbid = anchor.getAttribute('tbid'); var expanded = anchor.expanded; if (expanded) { hideElement(anchor.expandedElement); anchor.expanded = false; _swapImage(anchor); return false; } anchor.expanded = true; if (anchor.expandedElement) { showElement(anchor.expandedElement); _swapImage(anchor); $('#debug_input_'+tbid).get(0).focus(); return false; } var url = debug_base + '/show_frame?tbid=' + tbid + '&debugcount=' + debug_count; callbackXHR(url, null, function (data) { var el = createElement('div'); anchor.parentNode.insertBefore(el, anchor.nextSibling); el.innerHTML = data.responseText; anchor.expandedElement = el; _swapImage(anchor); $('#debug_input_'+tbid).focus().keydown(upArrow); }); return false; } function _swapImage(anchor) { var el = anchor.getElementsByTagName('IMG')[0]; if (anchor.expanded) { var img = 'minus.jpg'; } else { var img = 'plus.jpg'; } el.src = debug_base + '/media/' + img; } function showSource(anchor) { var location = anchor.getAttribute('location'); showSourceCode(location); return false; } function showSourceCode(location) { var url = debug_base + '/source_code?location=' + encodeURIComponent(location); var source = document.getElementById('source_data'); source.innerHTML = 'Loading...'; switch_display('source_data'); callbackXHR(url, null, function (req) { source.innerHTML = req.responseText; if (location.indexOf(':') > 0) { var lineno = location.substring(location.indexOf(':')+1); lineno = parseInt(lineno) - 10; if (lineno > 1) { document.location.hash = '#code-'+(lineno-10); } } }); } function submitInput(button, tbid) { var input = $('#' + button.getAttribute('input-from')).get(0); var output = $('#' + button.getAttribute('output-to')).get(0); var url = debug_base + '/exec_input'; var history = input.form.history; input.historyPosition = 0; if (! history) { history = input.form.history = []; } history.push(input.value); var vars = { tbid: tbid, debugcount: debug_count, input: input.value }; showElement(output); callbackXHR(url, vars, function (data) { var result = data.responseText; output.innerHTML += result; input.value = ''; input.focus(); }); return false; } function showError(msg) { var el = $('#error-container').get(0); if (el.innerHTML) { el.innerHTML += '
\n' + msg; } else { el.innerHTML = msg; } showElement($('#error-area').get(0)); } function clearError() { var el = $('#error-container').get(0); el.innerHTML = ''; $('#error-area').hide(); } function upArrow(event) { var key = event.charCode ? event.charCode : event.keyCode; if (key != 38 && key != 40 && key != 63232 && key != 63233) { // not an up- or down-arrow return true; } var dir = ((key == 38) || (key == 63232)) ? 1 : -1; var history = this.form.history; if (! history) { history = this.form.history = []; } var pos = this.historyPosition || 0; if (! pos && dir == -1) { return true; } if (! pos && this.value) { history.push(this.value); pos = 1; } pos += dir; if (history.length-pos < 0) { pos = 1; } if (history.length-pos > history.length-1) { this.value = ''; return true; } this.historyPosition = pos; var line = history[history.length-pos]; if (! line) { return true; } this.value = line; } function expandInput(button) { var input = button.form.elements.input; stdops = { name: 'input', style: 'width: 100%', autocomplete: 'off' }; if (input.tagName == 'INPUT') { var newEl = createElement('textarea', stdops); var text = 'Contract'; } else { stdops['type'] = 'text'; var newEl = createElement('input', stdops); $(newEl).keydown(upArrow); var text = 'Expand'; } newEl.value = input.value; newEl.id = input.id; swapDOM(input, newEl); newEl.focus(); button.value = text; return false; } function expandLong(anchor) { var span = anchor; while (span) { if (span.style && span.style.display == 'none') { break; } span = span.nextSibling; } if (! span) { return false; } showElement(span); hideElement(anchor); return false; } function showElement(el) { el.style.display = ''; } function hideElement(el) { el.style.display = 'none'; } function createElement(tag, attrs /*, sub-elements...*/) { var el = document.createElement(tag); if (attrs) { for (var i in attrs) { el.setAttribute(i, attrs[i]); } } for (var i=2; i' + name + '
'); } function switch_source(el, hide_type) { while (el) { if (el.getAttribute && el.getAttribute('source-type') == hide_type) { break; } el = el.parentNode; } if (! el) { return false; } el.style.display = 'none'; console.log('found current el', el); if (hide_type == 'long') { while (el) { if (el.getAttribute && el.getAttribute('source-type') == 'short') { break; } el = el.nextSibling; } console.log('found short el', el); } else { while (el) { if (el.getAttribute && el.getAttribute('source-type') == 'long') { break; } el = el.previousSibling; } console.log('found long el', el); } if (el) { el.style.display = ''; } return false; } $(document).ready(function() { var hide_all = function() { $('#short_text_version, #long_text_version, #short_traceback, #full_traceback, #short_xml_version, #long_xml_version, div.feature-highlight').hide(); $('#view_long_text, #view_short_text, #view_long_html, #view_short_html, #view_short_xml, #view_long_xml').removeClass('active'); }; if ($('#long_text_version').length == 0) { $('#view_long_text').hide(); } if ($('#full_traceback').length == 0) { $('#view_long_html').hide(); } $('#view_short_text').click(function() { hide_all(); $('#short_text_version').show(); $(this).addClass('active'); return false; }); $('#view_long_text').click(function() { hide_all(); $('#long_text_version').show(); $(this).addClass('active'); return false; }); $('#view_short_html').click(function() { hide_all(); $('#short_traceback, div.feature-highlight').show(); $(this).addClass('active'); return false; }); $('#view_long_html').click(function () { hide_all(); $('#full_traceback, div.feature-highlight').show(); $(this).addClass('active'); return false; }); $('#view_short_xml').click(function () { hide_all(); $('#short_xml_version').show(); $(this).addClass('active'); return false; }); $('#view_long_xml').click(function () { hide_all(); $('#long_xml_version').show(); $(this).addClass('active'); return false; }); }); /* Fix case when Firebug isn't present: */ if (typeof console == 'undefined') { var console = {log: function (msg) {}}; } WebError-0.10.3/weberror/eval-media/jquery-1.2.1.min.js 000664 000765 000024 00000132545 10770066101 022172 0 ustar 00ben staff 000000 000000 /* * jQuery 1.2.1 - New Wave Javascript * * Copyright (c) 2007 John Resig (jquery.com) * Dual licensed under the MIT (MIT-LICENSE.txt) * and GPL (GPL-LICENSE.txt) licenses. * * $Date: 2007-09-16 23:42:06 -0400 (Sun, 16 Sep 2007) $ * $Rev: 3353 $ */ (function(){if(typeof jQuery!="undefined")var _jQuery=jQuery;var jQuery=window.jQuery=function(selector,context){return this instanceof jQuery?this.init(selector,context):new jQuery(selector,context);};if(typeof $!="undefined")var _$=$;window.$=jQuery;var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(typeof selector=="string"){var m=quickExpr.exec(selector);if(m&&(m[1]||!context)){if(m[1])selector=jQuery.clean([m[1]],context);else{var tmp=document.getElementById(m[3]);if(tmp)if(tmp.id!=m[3])return jQuery().find(selector);else{this[0]=tmp;this.length=1;return this;}else selector=[];}}else return new jQuery(context).find(selector);}else if(jQuery.isFunction(selector))return new jQuery(document)[jQuery.fn.ready?"ready":"load"](selector);return this.setArray(selector.constructor==Array&&selector||(selector.jquery||selector.length&&selector!=window&&!selector.nodeType&&selector[0]!=undefined&&selector[0].nodeType)&&jQuery.makeArray(selector)||[selector]);},jquery:"1.2.1",size:function(){return this.length;},length:0,get:function(num){return num==undefined?jQuery.makeArray(this):this[num];},pushStack:function(a){var ret=jQuery(a);ret.prevObject=this;return ret;},setArray:function(a){this.length=0;Array.prototype.push.apply(this,a);return this;},each:function(fn,args){return jQuery.each(this,fn,args);},index:function(obj){var pos=-1;this.each(function(i){if(this==obj)pos=i;});return pos;},attr:function(key,value,type){var obj=key;if(key.constructor==String)if(value==undefined)return this.length&&jQuery[type||"attr"](this[0],key)||undefined;else{obj={};obj[key]=value;}return this.each(function(index){for(var prop in obj)jQuery.attr(type?this.style:this,prop,jQuery.prop(this,obj[prop],type,index,prop));});},css:function(key,value){return this.attr(key,value,"curCSS");},text:function(e){if(typeof e!="object"&&e!=null)return this.empty().append(document.createTextNode(e));var t="";jQuery.each(e||this,function(){jQuery.each(this.childNodes,function(){if(this.nodeType!=8)t+=this.nodeType!=1?this.nodeValue:jQuery.fn.text([this]);});});return t;},wrapAll:function(html){if(this[0])jQuery(html,this[0].ownerDocument).clone().insertBefore(this[0]).map(function(){var elem=this;while(elem.firstChild)elem=elem.firstChild;return elem;}).append(this);return this;},wrapInner:function(html){return this.each(function(){jQuery(this).contents().wrapAll(html);});},wrap:function(html){return this.each(function(){jQuery(this).wrapAll(html);});},append:function(){return this.domManip(arguments,true,1,function(a){this.appendChild(a);});},prepend:function(){return this.domManip(arguments,true,-1,function(a){this.insertBefore(a,this.firstChild);});},before:function(){return this.domManip(arguments,false,1,function(a){this.parentNode.insertBefore(a,this);});},after:function(){return this.domManip(arguments,false,-1,function(a){this.parentNode.insertBefore(a,this.nextSibling);});},end:function(){return this.prevObject||jQuery([]);},find:function(t){var data=jQuery.map(this,function(a){return jQuery.find(t,a);});return this.pushStack(/[^+>] [^+>]/.test(t)||t.indexOf("..")>-1?jQuery.unique(data):data);},clone:function(events){var ret=this.map(function(){return this.outerHTML?jQuery(this.outerHTML)[0]:this.cloneNode(true);});var clone=ret.find("*").andSelf().each(function(){if(this[expando]!=undefined)this[expando]=null;});if(events===true)this.find("*").andSelf().each(function(i){var events=jQuery.data(this,"events");for(var type in events)for(var handler in events[type])jQuery.event.add(clone[i],type,events[type][handler],events[type][handler].data);});return ret;},filter:function(t){return this.pushStack(jQuery.isFunction(t)&&jQuery.grep(this,function(el,index){return t.apply(el,[index]);})||jQuery.multiFilter(t,this));},not:function(t){return this.pushStack(t.constructor==String&&jQuery.multiFilter(t,this,true)||jQuery.grep(this,function(a){return(t.constructor==Array||t.jquery)?jQuery.inArray(a,t)<0:a!=t;}));},add:function(t){return this.pushStack(jQuery.merge(this.get(),t.constructor==String?jQuery(t).get():t.length!=undefined&&(!t.nodeName||jQuery.nodeName(t,"form"))?t:[t]));},is:function(expr){return expr?jQuery.multiFilter(expr,this).length>0:false;},hasClass:function(expr){return this.is("."+expr);},val:function(val){if(val==undefined){if(this.length){var elem=this[0];if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,a=[],options=elem.options,one=elem.type=="select-one";if(index<0)return null;for(var i=one?index:0,max=one?index+1:options.length;i=0||jQuery.inArray(this.name,val)>=0);else if(jQuery.nodeName(this,"select")){var tmp=val.constructor==Array?val:[val];jQuery("option",this).each(function(){this.selected=(jQuery.inArray(this.value,tmp)>=0||jQuery.inArray(this.text,tmp)>=0);});if(!tmp.length)this.selectedIndex=-1;}else this.value=val;});},html:function(val){return val==undefined?(this.length?this[0].innerHTML:null):this.empty().append(val);},replaceWith:function(val){return this.after(val).remove();},eq:function(i){return this.slice(i,i+1);},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments));},map:function(fn){return this.pushStack(jQuery.map(this,function(elem,i){return fn.call(elem,i,elem);}));},andSelf:function(){return this.add(this.prevObject);},domManip:function(args,table,dir,fn){var clone=this.length>1,a;return this.each(function(){if(!a){a=jQuery.clean(args,this.ownerDocument);if(dir<0)a.reverse();}var obj=this;if(table&&jQuery.nodeName(this,"table")&&jQuery.nodeName(a[0],"tr"))obj=this.getElementsByTagName("tbody")[0]||this.appendChild(document.createElement("tbody"));jQuery.each(a,function(){var elem=clone?this.cloneNode(true):this;if(!evalScript(0,elem))fn.call(obj,elem);});});}};function evalScript(i,elem){var script=jQuery.nodeName(elem,"script");if(script){if(elem.src)jQuery.ajax({url:elem.src,async:false,dataType:"script"});else jQuery.globalEval(elem.text||elem.textContent||elem.innerHTML||"");if(elem.parentNode)elem.parentNode.removeChild(elem);}else if(elem.nodeType==1)jQuery("script",elem).each(evalScript);return script;}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},a=1,al=arguments.length,deep=false;if(target.constructor==Boolean){deep=target;target=arguments[1]||{};}if(al==1){target=this;a=0;}var prop;for(;a -1;}},swap:function(e,o,f){for(var i in o){e.style["old"+i]=e.style[i];e.style[i]=o[i];}f.apply(e,[]);for(var i in o)e.style[i]=e.style["old"+i];},css:function(e,p){if(p=="height"||p=="width"){var old={},oHeight,oWidth,d=["Top","Bottom","Right","Left"];jQuery.each(d,function(){old["padding"+this]=0;old["border"+this+"Width"]=0;});jQuery.swap(e,old,function(){if(jQuery(e).is(':visible')){oHeight=e.offsetHeight;oWidth=e.offsetWidth;}else{e=jQuery(e.cloneNode(true)).find(":radio").removeAttr("checked").end().css({visibility:"hidden",position:"absolute",display:"block",right:"0",left:"0"}).appendTo(e.parentNode)[0];var parPos=jQuery.css(e.parentNode,"position")||"static";if(parPos=="static")e.parentNode.style.position="relative";oHeight=e.clientHeight;oWidth=e.clientWidth;if(parPos=="static")e.parentNode.style.position="static";e.parentNode.removeChild(e);}});return p=="height"?oHeight:oWidth;}return jQuery.curCSS(e,p);},curCSS:function(elem,prop,force){var ret,stack=[],swap=[];function color(a){if(!jQuery.browser.safari)return false;var ret=document.defaultView.getComputedStyle(a,null);return!ret||ret.getPropertyValue("color")=="";}if(prop=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(elem.style,"opacity");return ret==""?"1":ret;}if(prop.match(/float/i))prop=styleFloat;if(!force&&elem.style[prop])ret=elem.style[prop];else if(document.defaultView&&document.defaultView.getComputedStyle){if(prop.match(/float/i))prop="float";prop=prop.replace(/([A-Z])/g,"-$1").toLowerCase();var cur=document.defaultView.getComputedStyle(elem,null);if(cur&&!color(elem))ret=cur.getPropertyValue(prop);else{for(var a=elem;a&&color(a);a=a.parentNode)stack.unshift(a);for(a=0;a ]*?)\/>/g,function(m,all,tag){return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area)$/i)?m:all+">"+tag+">";});var s=jQuery.trim(arg).toLowerCase(),div=doc.createElement("div"),tb=[];var wrap=!s.indexOf(" ",""]||!s.indexOf(" ",""]||s.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1," ","
"]||!s.indexOf("",""]||(!s.indexOf(" "," "]||!s.indexOf(""," "]||jQuery.browser.msie&&[1,"div",""]||[0,"",""];div.innerHTML=wrap[1]+arg+wrap[2];while(wrap[0]--)div=div.lastChild;if(jQuery.browser.msie){if(!s.indexOf(""&&s.indexOf("=0;--n)if(jQuery.nodeName(tb[n],"tbody")&&!tb[n].childNodes.length)tb[n].parentNode.removeChild(tb[n]);if(/^\s/.test(arg))div.insertBefore(doc.createTextNode(arg.match(/^\s*/)[0]),div.firstChild);}arg=jQuery.makeArray(div.childNodes);}if(0===arg.length&&(!jQuery.nodeName(arg,"form")&&!jQuery.nodeName(arg,"select")))return;if(arg[0]==undefined||jQuery.nodeName(arg,"form")||arg.options)r.push(arg);else r=jQuery.merge(r,arg);});return r;},attr:function(elem,name,value){var fix=jQuery.isXMLDoc(elem)?{}:jQuery.props;if(name=="selected"&&jQuery.browser.safari)elem.parentNode.selectedIndex;if(fix[name]){if(value!=undefined)elem[fix[name]]=value;return elem[fix[name]];}else if(jQuery.browser.msie&&name=="style")return jQuery.attr(elem.style,"cssText",value);else if(value==undefined&&jQuery.browser.msie&&jQuery.nodeName(elem,"form")&&(name=="action"||name=="method"))return elem.getAttributeNode(name).nodeValue;else if(elem.tagName){if(value!=undefined){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode)throw"type property can't be changed";elem.setAttribute(name,value);}if(jQuery.browser.msie&&/href|src/.test(name)&&!jQuery.isXMLDoc(elem))return elem.getAttribute(name,2);return elem.getAttribute(name);}else{if(name=="opacity"&&jQuery.browser.msie){if(value!=undefined){elem.zoom=1;elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseFloat(value).toString()=="NaN"?"":"alpha(opacity="+value*100+")");}return elem.filter?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100).toString():"";}name=name.replace(/-([a-z])/ig,function(z,b){return b.toUpperCase();});if(value!=undefined)elem[name]=value;return elem[name];}},trim:function(t){return(t||"").replace(/^\s+|\s+$/g,"");},makeArray:function(a){var r=[];if(typeof a!="array")for(var i=0,al=a.length;i
\\s*("+chars+"+)"),quickID=new RegExp("^("+chars+"+)(#)("+chars+"+)"),quickClass=new RegExp("^([#.]?)("+chars+"*)");jQuery.extend({expr:{"":"m[2]=='*'||jQuery.nodeName(a,m[2])","#":"a.getAttribute('id')==m[2]",":":{lt:"i m[3]-0",nth:"m[3]-0==i",eq:"m[3]-0==i",first:"i==0",last:"i==r.length-1",even:"i%2==0",odd:"i%2","first-child":"a.parentNode.getElementsByTagName('*')[0]==a","last-child":"jQuery.nth(a.parentNode.lastChild,1,'previousSibling')==a","only-child":"!jQuery.nth(a.parentNode.lastChild,2,'previousSibling')",parent:"a.firstChild",empty:"!a.firstChild",contains:"(a.textContent||a.innerText||jQuery(a).text()||'').indexOf(m[3])>=0",visible:'"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden"',hidden:'"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden"',enabled:"!a.disabled",disabled:"a.disabled",checked:"a.checked",selected:"a.selected||jQuery.attr(a,'selected')",text:"'text'==a.type",radio:"'radio'==a.type",checkbox:"'checkbox'==a.type",file:"'file'==a.type",password:"'password'==a.type",submit:"'submit'==a.type",image:"'image'==a.type",reset:"'reset'==a.type",button:'"button"==a.type||jQuery.nodeName(a,"button")',input:"/input|select|textarea|button/i.test(a.nodeName)",has:"jQuery.find(m[3],a).length",header:"/h\\d/i.test(a.nodeName)",animated:"jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length"}},parse:[/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,new RegExp("^([:.#]*)("+chars+"+)")],multiFilter:function(expr,elems,not){var old,cur=[];while(expr&&expr!=old){old=expr;var f=jQuery.filter(expr,elems,not);expr=f.t.replace(/^\s*,\s*/,"");cur=not?elems=f.r:jQuery.merge(cur,f.r);}return cur;},find:function(t,context){if(typeof t!="string")return[t];if(context&&!context.nodeType)context=null;context=context||document;var ret=[context],done=[],last;while(t&&last!=t){var r=[];last=t;t=jQuery.trim(t);var foundToken=false;var re=quickChild;var m=re.exec(t);if(m){var nodeName=m[1].toUpperCase();for(var i=0;ret[i];i++)for(var c=ret[i].firstChild;c;c=c.nextSibling)if(c.nodeType==1&&(nodeName=="*"||c.nodeName.toUpperCase()==nodeName.toUpperCase()))r.push(c);ret=r;t=t.replace(re,"");if(t.indexOf(" ")==0)continue;foundToken=true;}else{re=/^([>+~])\s*(\w*)/i;if((m=re.exec(t))!=null){r=[];var nodeName=m[2],merge={};m=m[1];for(var j=0,rl=ret.length;j =0;if(!not&&pass||not&&!pass)tmp.push(r[i]);}return tmp;},filter:function(t,r,not){var last;while(t&&t!=last){last=t;var p=jQuery.parse,m;for(var i=0;p[i];i++){m=p[i].exec(t);if(m){t=t.substring(m[0].length);m[2]=m[2].replace(/\\/g,"");break;}}if(!m)break;if(m[1]==":"&&m[2]=="not")r=jQuery.filter(m[3],r,true).r;else if(m[1]==".")r=jQuery.classFilter(r,m[2],not);else if(m[1]=="["){var tmp=[],type=m[3];for(var i=0,rl=r.length;i =0)^not)tmp.push(a);}r=tmp;}else if(m[1]==":"&&m[2]=="nth-child"){var merge={},tmp=[],test=/(\d*)n\+?(\d*)/.exec(m[3]=="even"&&"2n"||m[3]=="odd"&&"2n+1"||!/\D/.test(m[3])&&"n+"+m[3]||m[3]),first=(test[1]||1)-0,last=test[2]-0;for(var i=0,rl=r.length;i <\/script>");var script=document.getElementById("__ie_init");if(script)script.onreadystatechange=function(){if(this.readyState!="complete")return;jQuery.ready();};script=null;}else if(jQuery.browser.safari)jQuery.safariTimer=setInterval(function(){if(document.readyState=="loaded"||document.readyState=="complete"){clearInterval(jQuery.safariTimer);jQuery.safariTimer=null;jQuery.ready();}},10);jQuery.event.add(window,"load",jQuery.ready);}jQuery.fn.extend({load:function(url,params,callback){if(jQuery.isFunction(url))return this.bind("load",url);var off=url.indexOf(" ");if(off>=0){var selector=url.slice(off,url.length);url=url.slice(0,off);}callback=callback||function(){};var type="GET";if(params)if(jQuery.isFunction(params)){callback=params;params=null;}else{params=jQuery.param(params);type="POST";}var self=this;jQuery.ajax({url:url,type:type,data:params,complete:function(res,status){if(status=="success"||status=="notmodified")self.html(selector?jQuery("").append(res.responseText.replace(/