Analyzer::Python::Flask
Inherits Analyzer::Python::PythonEngine < Analyzer < FileHelper < Reference < Object
Constants
flask_restful / flask-restx register class-based Resources with
api.add_resource(ResourceClass, "/url"[, "/url2"], endpoint=...).
Each Resource exposes one endpoint per HTTP-verb method it defines.
Hoisted for the common (alias-free) case so the per-file regex isn't
recompiled; ADD_RESOURCE_SUBSTRING is the cheap per-line guard.
Decorator-based Python web frameworks whose route syntax is
indistinguishable from Flask's at the line level — @app.get("/x"),
@api.post("/x"). A file that imports one of these and never mentions
flask belongs to that framework's analyzer. ninja (Django Ninja),
bottle and aiohttp were missing from the list, so the Flask analyzer
claimed their handler files and relabelled the routes python_flask
with Flask-shaped (usually empty) params.
Per-line route-discovery patterns. These interpolate only the
PYTHON_VAR_NAME_REGEX/DOT_NATION constants, so the inline literals
were recompiling identical PCRE2 patterns on every source line of
every file (analyze runs them per line). Compile once here; the
.to_s expansion of the interpolated constants is byte-identical
to the previous inline form, so matching behaviour is unchanged.
extract_request_params runs once per route and used to rebuild
two PCRE2 patterns per request field on every call (8 fields × 2 =
16 regex compilations per endpoint). PCRE2 JIT-compilation of an
interpolated regex literal is ~3µs and dominated Flask scan time
(profiling: ~50% of the analyzer). The field names are a fixed set,
so precompile the access patterns once here and reuse them.
Tuple shape: {noir_param_type, bracket_access_regex, get_access_regex}
The get-access pattern accepts .get( and .getlist(: Werkzeug's
request MultiDicts (request.args, request.form, …) expose
getlist("key") as the standard accessor for repeated keys
(?tag=a&tag=b), and it reads the same first string argument as the
key — so .get(?:list)? captures both without a separate pattern.
Reference: https://stackoverflow.com/a/16664376 Reference: https://tedboy.github.io/flask/generated/generated/flask.Request.html
QUERY (RFC 10008) is safe/idempotent like GET but, per the method's
whole purpose, carries its filter criteria in a request body like
POST — so it joins the body-bearing methods for "form"/"json", not
the read-only "query" (query-string) type.
def add_x(self, resource, ...) head of an Api-subclass method that
may wrap add_resource (e.g. redash's add_org_resource).
Source-ownership and add_url_rule helpers — same constant-only interpolation (DOT_NATION), hoisted so the per-file/per-call sites don't recompile them. VIEW_FUNC_KWARG_RE has no whitespace tolerance (unlike Quart's) because Flask's add_url_rule args are matched on space-stripped lines.
view_func= extractors for the add_url_rule scan below — same
constant-only interpolation, hoisted so they aren't rebuilt on every
add_url_rule(...) match found in a file.
Class methods
Instance methods
Create a Python parser for a given path and content. The parser walks the file with tree-sitter and recursively absorbs globals from imported modules — no lexer step.
Extracts parameters from the decorator
Extracts endpoint information from the given route and code block
Filters the parameters based on the HTTP method
Instance-side view of the same declaration. The per-file rescues live on
this base class, which has no way to name the analyzer that is running
inside them, so a skipped file could not be attributed to a tech.
Deriving it from analyzer_for keeps the name written exactly once.