From hi at jnnkb.eu Fri Dec 3 07:54:04 2021 From: hi at jnnkb.eu (jnnk) Date: Fri, 3 Dec 2021 13:54:04 +0100 Subject: [Flask] URL Map Converters Message-ID: <9E31C121-6329-430D-B49C-40E056F33703@jnnkb.eu> Hey everybody, I yesterday tried using an IDSlugConverter similar to this with a current version of Werkzeug, which worked without any problems until 0.16.0. Unfortuantly any version >= 1.0.0 leads to the following error: File "", line 1, in '> File "test_urlmap_converter/flask_app.py", line 20, in to_url return f"{value.id}/{value.filename}" AttributeError: 'int' object has no attribute ?id? I create the following minimal example to illustrate the problem. The error occurs when navigating to /files/3/hey.txt. from flask import Flask, url_for from werkzeug.routing import BaseConverter class File: def __init__(self, id_, filename): self.id = id_ self.filename = filename class IDSlugConverter(BaseConverter): """Matches an int id and optional slug, separated by "/".""" regex = r"-?\d+(?:/[\w\-]*.\w*)?" def to_python(self, value): return int((value.split("/"))[0]) def to_url(self, value): return f"{value.id}/{value.filename}" app = Flask(__name__) app.url_map.converters["id_slug"] = IDSlugConverter @app.route("/") def index(): url = url_for("serve_file", id=File(3, "hey.txt")) return f'Bild' @app.route("/files/") def serve_file(id): return "fancy file" It seems like these converters now require that to_python and to_url are inverses. Is this intended? Since I?m using this with different model classes I otherwise would have to use some magic like below to prevent circular imports. (See attached app.zip) def __init__(self, url_map, model): module, variable = model.rsplit(".", 1) self.model = getattr(sys.modules[module], variable) super().__init__(url_map) With kind regards, jnnk -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: app.zip Type: application/zip Size: 10012 bytes Desc: not available URL: -------------- next part -------------- An HTML attachment was scrubbed... URL: From skip.montanaro at gmail.com Mon Dec 27 06:32:45 2021 From: skip.montanaro at gmail.com (Skip Montanaro) Date: Mon, 27 Dec 2021 05:32:45 -0600 Subject: [Flask] Confused by an unexpected route-to-function mapping Message-ID: I'm returning to Flask after several years away (and never having done much of any significance with it before). I'm having trouble with the mapping between routes and the functions which handle them. I have two functions, each of which is meant to handle a number of related routes. The first is just supposed to normalize things and do a permanent redirect to the second @app.route('/-/html/') @app.route('/CR/-/html/') @app.route('/-') @app.route('/-/') def old_cr_month(year, month, filename="index.html"): print(">> old_cr_month:", year, month, filename) raise Exception return redirect(url_for("cr", year=year, month=month, filename=filename), code=301) @app.route("/CR") @app.route("/CR/") @app.route('/CR//') @app.route('/CR///') def cr(year=None, month=None, filename="index.html"): print(">> cr:", year, month, filename) ... When I visit this URL: http://super.secret.website/CR/2000-09/html/maillist.html old_cr_month is called, as I expect. Its print function is called and the embedded exception is raised. When I visit this URL: http://super.secret.website/CR/2000-09/html/threads.html the old_cr_month handler isn't called. Instead, the cr function is enlisted to handle the request and its print function is called. Strangely, it does seem to get year, month and filename correct. This despite none of the defined routes for cr having URL templates with either the year-month form or an embedded html directory in the middle. When I dump the app object in the debugger the displayed url_map looks to me like old_cr_month should have handled the URL (my candidate route mapping highlighted in red). Map([ hello>, cr>, cr>, index>, -/html/' (HEAD, OPTIONS, GET) -> old_cr_month>, -/html/' (HEAD, OPTIONS, GET) -> old_cr_month>, ' (HEAD, OPTIONS, GET) -> static>, //' (HEAD, OPTIONS, GET) -> cr_message>, //' (HEAD, OPTIONS, GET) -> cr>, /' (HEAD, OPTIONS, GET) -> cr>, -/' (HEAD, OPTIONS, GET) -> old_cr_month>, -' (HEAD, OPTIONS, GET) -> old_cr_month>]) Here's my setup: $ flask --version Python 3.10.1 Flask 2.0.2 Werkzeug 2.0.2 I'm running in an Ubuntu 20.04 VM. What am I missing about routes here? How can two so similarly structured URLs be mapped to different handler functions? Is there something I can do to dig into the URL-to-handler mapping process? Thx, Skip Montanaro -------------- next part -------------- An HTML attachment was scrubbed... URL: