class
Analyzer::Python::Flask
Defined in:
analyzer/analyzers/python/flask.crConstant Summary
-
ADD_RESOURCE_RE =
/(#{PYTHON_VAR_NAME_REGEX})\s*\.\s*add_resource\s*\((.+)\)/m -
flask_restful / flask-restx register class-based
Resources withapi.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_SUBSTRINGis the cheap per-line guard. -
ADD_RESOURCE_SUBSTRINGS =
[".add_resource("] -
ADD_URL_RULE_RE =
/(#{PYTHON_VAR_NAME_REGEX})\.add_url_rule\((.+)\)/m -
DOTTED_REFERENCE_RE =
/^#{DOT_NATION}$/ -
FLASK_INSTANCE_RE =
/(#{PYTHON_VAR_NAME_REGEX})(?::#{DOT_NATION})?=(?:flask\.)?Flask\(/ -
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 (
#analyzeruns them per line). Compile once here; the.to_sexpansion of the interpolated constants is byte-identical to the previous inline form, so matching behaviour is unchanged. -
INIT_APP_RE =
/(#{PYTHON_VAR_NAME_REGEX})\.init_app\((#{PYTHON_VAR_NAME_REGEX})/ -
REGISTER_BLUEPRINT_RE =
/(#{PYTHON_VAR_NAME_REGEX})\.register_blueprint\((#{DOT_NATION})/ -
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\\([rf]?['\"]([^'\"]*)['\"]")} end -
extract_request_paramsruns 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} -
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
-
REQUEST_PARAM_TYPES =
{"query" => nil, "form" => ["POST", "PUT", "PATCH", "DELETE"], "json" => ["POST", "PUT", "PATCH", "DELETE"], "cookie" => nil, "header" => nil} -
RESOURCE_REGISTRAR_DEF_RE =
/^(\s*)(?:async\s+)?def\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(\s*self\s*,\s*resource\b/ -
def add_x(self, resource, ...)head of an Api-subclass method that may wrapadd_resource(e.g. redash'sadd_org_resource). -
ROUTE_DECORATOR_RE =
/^\s*@\s*#{DOT_NATION}\s*\.\s*(?:route|get|post|put|patch|delete|head|options|trace)\s*\(/m -
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.
-
ROUTE_REGISTRAR_RE =
/\b#{DOT_NATION}\s*\.\s*(?:add_url_rule|register_blueprint)\s*\(/ -
VIEW_ASSIGN_RE =
/(#{PYTHON_VAR_NAME_REGEX})(?::#{DOT_NATION})?=(#{PYTHON_VAR_NAME_REGEX})\.as_view\(/ -
VIEW_FUNC_KWARG_RE =
/view_func=(#{DOT_NATION})(?:,|\)|$)/
Instance Method Summary
- #analyze
-
#create_parser(path : String, content : String = "") : PythonParser
Create a Python parser for a given path and content.
-
#extract_params_from_decorator(path : String, lines : Array(String), line_index : Int32, direction : Symbol = :down) : Tuple(Array(Param), Int32)
Extracts parameters from the decorator
-
#get_endpoints(method : String, route_path : String, extra_params : String, codeblock_lines : Array(String), prefix : String)
Extracts endpoint information from the given route and code block
-
#get_filtered_params(method : String, params : Array(Param)) : Array(Param)
Filters the parameters based on the HTTP method
-
#get_parser(path : String, content : String = "") : PythonParser
Get a parser for a given path
Instance methods inherited from class Analyzer::Python::PythonEngine
build_callees_from(body : String, body_start_line : Int32, path : String, *, definition_base_path : String | Nil = nil, source : String | Nil = nil) : Array(Callee)
build_callees_from,
find_def_line(lines : Array(String), decorator_line : Int32) : Int32 | Nil
find_def_line,
find_imported_modules(app_base_path : String, file_path : String, content : String | Nil = nil) : Hash(String, Tuple(String, Int32))
find_imported_modules,
find_imported_package(package_path : String, dotted_as_names : String) : Array(Tuple(String, String, Int32))
find_imported_package,
find_json_params(codeblock_lines : Array(String), json_var_names : Array(String)) : Array(Param)
find_json_params,
join_until_python_call_closes(lines : Array(String), index : Int32, line : String) : String
join_until_python_call_closes,
parse_code_block(data : String | Array(String), after : Regex | Nil = nil) : String | Nil
parse_code_block,
parse_function_def(source_lines : Array(String), start_index : Int32) : FunctionDefinition | Nil
parse_function_def,
push_callees_from(endpoint : Endpoint, body : String, body_start_line : Int32, path : String, *, definition_base_path : String | Nil = nil, source : String | Nil = nil) : Nil
push_callees_from,
python_paren_delta(line : String) : Int32
python_paren_delta,
python_signature_line_span(lines : Array(String)) : Int32
python_signature_line_span,
return_literal_value(data : String) : String
return_literal_value
Class methods inherited from class Analyzer::Python::PythonEngine
python_test_path?(path : String, base_path : String | Nil = nil) : Bool
python_test_path?
Instance methods inherited from class Analyzer
analyze
analyze,
base_path : String
base_path,
base_paths : Array(String)
base_paths,
callees_needed? : Bool
callees_needed?,
logger : NoirLogger
logger,
parallel_analyze(files : Array(String), &block : String -> Nil)
parallel_analyze,
read_file_content(path : String) : String
read_file_content,
result : Array(Endpoint)
result,
url : String
url
Constructor methods inherited from class Analyzer
new(options : Hash(String, YAML::Any))
new
Macros inherited from class Analyzer
define_getter_methods(names)
define_getter_methods
Instance methods inherited from module FileHelper
all_files : Array(String)
all_files,
get_files_by_extension(extension : String) : Array(String)
get_files_by_extension,
get_files_by_prefix(prefix : String) : Array(String)
get_files_by_prefix,
get_files_by_prefix_and_extension(prefix : String, extension : String) : Array(String)
get_files_by_prefix_and_extension,
get_public_dir_files(base_path : String, folder : String) : Array(String)
get_public_dir_files,
get_public_files(base_path : String, anchors : Array(String) = ["shard.yml", "Gemfile"]) : Array(String)
get_public_files
Instance Method Detail
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
Get a parser for a given path