diff --git a/.gitignore b/.gitignore index d7f7a42..0c4323f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .mypy_cache +__pycache__ diff --git a/main.py b/main.py index 36e910a..154b71e 100755 --- a/main.py +++ b/main.py @@ -1,70 +1,78 @@ #!/usr/bin/python3 +"""Find photos on flickr for Wikipedia articles and contact the photographer.""" import collections +import inspect import json import sys +import traceback import typing from urllib.parse import unquote import flask import requests +import werkzeug +from werkzeug.debug.tbtools import DebugTraceback app = flask.Flask(__name__) -app.debug = True +app.debug = False enwiki = "en.wikipedia.org/wiki/" +@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 = 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 start() -> str: """Start form.""" - return flask.render_template("wikipedia_url.html") - - -@app.route("/flickr") -def flickr_search() -> str: - """Search flickr.""" - wikipedia_url = flask.request.args["wikipedia"] - start = wikipedia_url.find(enwiki) + len(enwiki) - name = unquote(wikipedia_url[start:]).replace("_", " ") - return flask.render_template( - "flickr_search.html", name=name, wikipedia_url=wikipedia_url - ) - - -def get_params(line_iter: collections.abc.Iterable[str]) -> str: - """Find and return params from flickr profile page.""" - look_for = 'params: {"isEditingTestimonial":false,' - return next(line[line.find("{") :] for line in line_iter if look_for in line) - - -def flickr_usrename_to_nsid(username: str) -> str: - """Get NSID from flickr username.""" - url = f"https://www.flickr.com/people/{username}/" - r = requests.get(url) - params = json.loads(get_params(r.text.splitlines())) - return typing.cast(str, params["nsid"]) - - -@app.route("/message") -def show_message() -> str: - """Show message.""" - flickr_url = flask.request.args["flickr"] - wikipedia_url = flask.request.args["wikipedia"] + wikipedia_url = flask.request.args.get("wikipedia") + if not wikipedia_url: + return flask.render_template("combined.html") start = wikipedia_url.find(enwiki) + len(enwiki) - wiki_part1 = wikipedia_url[:start] + wiki_part2 = unquote(wikipedia_url[start:]) - if len(sys.argv) > 4: - name = sys.argv[4] - else: - wiki_part2 = unquote(wikipedia_url[start:]) - name = wiki_part2 + name = wiki_part2 if "_(" in name: name = name[: name.find("_(")] name = name.replace("_", " ") + flickr_url = flask.request.args.get("flickr") + if not flickr_url: + return flask.render_template( + "combined.html", + name=name, + wikipedia_url=wikipedia_url, + ) + + wiki_part1 = wikipedia_url[:start] + if "/in/" in flickr_url: flickr_url = flickr_url[: flickr_url.find("/in/")] @@ -93,9 +101,29 @@ def show_message() -> str: lines = msg.split("\n\n") return flask.render_template( - "show_message.html", subject=subject, lines=lines, nsid=nsid + "combined.html", + name=name, + wikipedia_url=wikipedia_url, + flickr_url=flickr_url, + subject=subject, + lines=lines, + nsid=nsid, ) +def get_params(line_iter: collections.abc.Iterable[str]) -> str: + """Find and return params from flickr profile page.""" + look_for = 'params: {"isEditingTestimonial":false,' + return next(line[line.find("{") :] for line in line_iter if look_for in line) + + +def flickr_usrename_to_nsid(username: str) -> str: + """Get NSID from flickr username.""" + url = f"https://www.flickr.com/people/{username}/" + r = requests.get(url) + params = json.loads(get_params(r.text.splitlines())) + return typing.cast(str, params["nsid"]) + + if __name__ == "__main__": app.run(host="0.0.0.0") 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/start_form.html b/templates/base.html similarity index 50% rename from templates/start_form.html rename to templates/base.html index 67e0862..5f2d87e 100644 --- a/templates/start_form.html +++ b/templates/base.html @@ -1,32 +1,25 @@ - +
-Wikipedia article: {{ name }}
+ + + + + {% endif %} + + {% if flickr_url %} +{{ p }}
+ {% endfor %} +{{ exception }}
+Error in function "{{ last_frame.f_code.co_name }}": {{ last_frame_args | pprint }}
+{{ last_frame.f_locals | pprint }}
+
+