diff --git a/static/css/exception.css b/static/css/exception.css new file mode 100644 index 0000000..1f141c5 --- /dev/null +++ b/static/css/exception.css @@ -0,0 +1,78 @@ +div.debugger { text-align: left; padding: 12px; margin: auto; + background-color: white; } +div.detail { cursor: pointer; } +div.detail p { margin: 0 0 8px 13px; font-size: 14px; white-space: pre-wrap; + font-family: monospace; } +div.explanation { margin: 20px 13px; font-size: 15px; color: #555; } +div.footer { font-size: 13px; text-align: right; margin: 30px 0; + color: #86989B; } + +h2 { font-size: 16px; margin: 1.3em 0 0.0 0; padding: 9px; + background-color: #11557C; color: white; } +h2 em, h3 em { font-style: normal; color: #A5D6D9; font-weight: normal; } + +div.traceback, div.plain { border: 1px solid #ddd; margin: 0 0 1em 0; padding: 10px; } +div.plain p { margin: 0; } +div.plain textarea, +div.plain pre { margin: 10px 0 0 0; padding: 4px; + background-color: #E8EFF0; border: 1px solid #D3E7E9; } +div.plain textarea { width: 99%; height: 300px; } +div.traceback h3 { font-size: 1em; margin: 0 0 0.8em 0; } +div.traceback ul { list-style: none; margin: 0; padding: 0 0 0 1em; } +div.traceback h4 { font-size: 13px; font-weight: normal; margin: 0.7em 0 0.1em 0; } +div.traceback pre { margin: 0; padding: 5px 0 3px 15px; + background-color: #E8EFF0; border: 1px solid #D3E7E9; } +div.traceback .library .current { background: white; color: #555; } +div.traceback .expanded .current { background: #E8EFF0; color: black; } +div.traceback pre:hover { background-color: #DDECEE; color: black; cursor: pointer; } +div.traceback div.source.expanded pre + pre { border-top: none; } + +div.traceback span.ws { display: none; } +div.traceback pre.before, div.traceback pre.after { display: none; background: white; } +div.traceback div.source.expanded pre.before, +div.traceback div.source.expanded pre.after { + display: block; +} + +div.traceback div.source.expanded span.ws { + display: inline; +} + +div.traceback blockquote { margin: 1em 0 0 0; padding: 0; white-space: pre-line; } +div.traceback img { float: right; padding: 2px; margin: -3px 2px 0 0; display: none; } +div.traceback img:hover { background-color: #ddd; cursor: pointer; + border-color: #BFDDE0; } +div.traceback pre:hover img { display: block; } +div.traceback cite.filename { font-style: normal; color: #3B666B; } + +pre.console { border: 1px solid #ccc; background: white!important; + color: black; padding: 5px!important; + margin: 3px 0 0 0!important; cursor: default!important; + max-height: 400px; overflow: auto; } +pre.console form { color: #555; } +pre.console input { background-color: transparent; color: #555; + width: 90%; font-family: 'Consolas', 'Deja Vu Sans Mono', + 'Bitstream Vera Sans Mono', monospace; font-size: 14px; + border: none!important; } + +span.string { color: #30799B; } +span.number { color: #9C1A1C; } +span.help { color: #3A7734; } +span.object { color: #485F6E; } +span.extended { opacity: 0.5; } +span.extended:hover { opacity: 1; } +a.toggle { text-decoration: none; background-repeat: no-repeat; + background-position: center center; + background-image: url(?__debugger__=yes&cmd=resource&f=more.png); } +a.toggle:hover { background-color: #444; } +a.open { background-image: url(?__debugger__=yes&cmd=resource&f=less.png); } + +div.traceback pre, div.console pre { + white-space: pre-wrap; /* css-3 should we be so lucky... */ + white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ + white-space: -pre-wrap; /* Opera 4-6 ?? */ + white-space: -o-pre-wrap; /* Opera 7 ?? */ + word-wrap: break-word; /* Internet Explorer 5.5+ */ + _white-space: pre; /* IE only hack to re-specify in + addition to word-wrap */ +} diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..8452f57 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,22 @@ + + + + + + +{% block title %}{% endblock %} + + + +{% block style %} +{% endblock %} + + + +{% block content %} +{% endblock %} + +{% block scripts %} +{% endblock %} + + diff --git a/templates/show_error.html b/templates/show_error.html new file mode 100644 index 0000000..dd79c3c --- /dev/null +++ b/templates/show_error.html @@ -0,0 +1,23 @@ +{% extends "base.html" %} + +{% block style %} + +{% endblock %} + +{% block content %} +
+ +

Software error: {{ exception_type }}

+
+
{{ exception }}
+
+ +

Traceback (most recent call last)

+{{ summary | safe }} + +

Error in function "{{ last_frame.f_code.co_name }}": {{ last_frame_args | pprint }}

+
{{ last_frame.f_locals | pprint }}
+ +
+ +{% endblock %} diff --git a/web_view.py b/web_view.py index a76ca5c..1001d2d 100755 --- a/web_view.py +++ b/web_view.py @@ -2,16 +2,48 @@ """Web page to show upcoming events.""" +import inspect +import sys +import traceback from datetime import date, datetime, timezone -from flask import Flask, render_template +import flask +import werkzeug +import werkzeug.debug.tbtools from agenda import get_data -app = Flask(__name__) +app = flask.Flask(__name__) app.debug = True +@app.errorhandler(werkzeug.exceptions.InternalServerError) +def exception_handler(e: werkzeug.exceptions.InternalServerError) -> tuple[str, int]: + """Handle exception.""" + exec_type, exc_value, current_traceback = sys.exc_info() + assert exc_value + tb = werkzeug.debug.tbtools.DebugTraceback(exc_value) + + summary = tb.render_traceback_html(include_title=False) + exc_lines = "".join(tb._te.format_exception_only()) + + last_frame = list(traceback.walk_tb(current_traceback))[-1][0] + last_frame_args = inspect.getargs(last_frame.f_code) + + return ( + flask.render_template( + "show_error.html", + plaintext=tb.render_traceback_text(), + exception=exc_lines, + exception_type=tb._te.exc_type.__name__, + summary=summary, + last_frame=last_frame, + last_frame_args=last_frame_args, + ), + 500, + ) + + @app.route("/") def index() -> str: """Index page.""" @@ -27,7 +59,7 @@ def index() -> str: def days(when: date) -> str: return "today" if when == today else f"{(when - today).days:,d} days" - return render_template("index.html", days=days, days_hours=days_hours, **data) + return flask.render_template("index.html", days=days, days_hours=days_hours, **data) if __name__ == "__main__":