module

Analyzer::Python::FlaskFamily

State and helpers shared by the Flask and Quart analyzers: Quart re-implements Flask's API 1:1 (request object, Blueprints, add_url_rule, class-based views), so both read sources the same way.

Constants

FUNCTION_DEF_RE = /^\s*(?:async\s+)?def\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(/
REQUEST_FIELD_ALIAS_RE = /\A\s*([a-zA-Z_]\w*)\s*(?::[^=]+)?=\s*(?:await\s+)?request\.(form|args|values|files|headers|cookies)(?:\.to_dict\([^)]*\))?(?![\w.\[(]|\s+[.\[(])/

data = request.form (or await request.form, .to_dict(), request.form or {}): reads through data[...] / data.get(...) are that field's params. Not name = request.form.get("name"), which binds one value, nor a form=request.form keyword argument.

REQUEST_PARAM_FIELD_PATTERNS = REQUEST_PARAM_FIELDS.map do |field_name, tuple| {tuple[1], Regex.new("request\\.#{field_name}\\[[rf]?['\"]([^'\"]*)['\"]\\]"), Regex.new("request\\.#{field_name}\\.get(?:list)?\\([rf]?['\"]([^'\"]*)['\"]")} end

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.

REQUEST_PARAM_FIELDS = {"data" => {["POST", "PUT", "PATCH", "DELETE"], "form"}, "args" => {["GET"], "query"}, "form" => {["POST", "PUT", "PATCH", "DELETE"], "form"}, "files" => {["POST", "PUT", "PATCH", "DELETE"], "form"}, "values" => {["GET", "POST", "PUT", "PATCH", "DELETE"], "query"}, "json" => {["POST", "PUT", "PATCH", "DELETE"], "json"}, "cookies" => {nil, "cookie"}, "headers" => {nil, "header"}}

Reference: https://stackoverflow.com/a/16664376 Reference: https://tedboy.github.io/flask/generated/generated/flask.Request.html

Instance methods

create_parser(path : String, content : String = "") : PythonParser

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.

Source
get_endpoints(method : String, route_path : String, extra_params : String, codeblock_lines : Array(String), prefix : String)

Build endpoints from a single route decoration: split on declared methods=[...], default to method, run the analyzer's own extract_request_params over the handler body once and filter the params per method.

Source
get_parser(path : String, content : String = "") : PythonParser

Get a parser for a given path

Source