class

Analyzer::Python::Litestar

Inherits Analyzer::Python::PythonEngine < Analyzer < FileHelper < Reference < Object

Constants

BODY_MODEL_RE = /\A\s*([A-Z][A-Za-z0-9_]*)\s*\z/
CLASS_HEAD_RE = /^\s*class\s+(#{PYTHON_VAR_NAME_REGEX})\s*\(/
CONTROLLER_CLASS_RE = /^\s*class\s+(#{PYTHON_VAR_NAME_REGEX})\s*\(([^)]*)\)/
DECORATOR_PATH_KW_REGEX = /path\s*=\s*[rf]?['"]([^'"]*)['"]/
DECORATOR_PATH_LIST_KW_RE = /path\s*=\s*\[([^\]]*)\]/
DECORATOR_PATH_LIST_REGEX = /^\s*\[([^\]]*)\]/
DECORATOR_PATH_REGEX = /^\s*[rf]?['"]([^'"]*)['"]/

Path literal inside a decorator. Litestar accepts both a positional path and an explicit path= keyword argument. List forms (@get(["/a", "/b"]), @get(path=["/a", "/b"])) and omitted paths (@get(), @get(sync_to_thread=False) → default "" / /) are handled by extract_decorator_paths.

DECORATOR_REGEX = /@(get|post|put|patch|delete|head|options|route|websocket(?:_listener|_stream)?)\s*\((#{PYTHON_CALL_ARGS})/

Decorator matching: @get("/path"), @post("/path"), etc. The tail after the path literal is captured so extra kwargs (like methods=) can be inspected for multi-method @route decorators. websocket(?:_listener|_stream)? also matches Litestar's @websocket_listener("/ws") and @websocket_stream("/ws") decorators (the listener/stream class-based WS handlers), which take a positional path just like @websocket — without the variants every listener/stream endpoint was silently dropped.

DEPENDENCIES_LINE_RE = /\bdependencies\s*[:=]/
DEPENDENCY_KEY_RE = /\bkey\s*=\s*['"]([A-Za-z_]\w*)['"]/
DOTTED_HANDLER_RE = /(#{PYTHON_VAR_NAME_REGEX})\.(#{PYTHON_VAR_NAME_REGEX})/

Hoisted out of the per-line/per-param loops: an interpolated regex literal recompiles (PCRE2 JIT) on every evaluation, and these interpolate only constants or fixed sets. The .to_s expansion is byte-identical to the previous inline form, so matching behaviour is unchanged.

FORM_ENCODING_RE = /RequestEncodingType\.(?:URL_ENCODED|MULTI_PART)/
HTTP_METHOD_ITEM_REGEX = /['"]([A-Za-z]+)['"]|HttpMethod\.([A-Za-z]+)/

One verb in an http_method=[...] list: "POST" or HttpMethod.POST.

HTTP_METHOD_KW_REGEX = /http_method\s*=\s*(?:[\[(]([^\])]*)[\])]|['"]([^'"]+)['"]|HttpMethod\.([A-Za-z]+))/
LITESTAR_APP_RE = /\bLitestar\s*\(/
MODEL_FIELD_RE = /^([A-Za-z_]\w*)\s*:\s*(.+)$/
MODEL_ROOT_BASES = Set {"BaseModel", "Struct", "msgspec.Struct", "pydantic.BaseModel", "object", "TypedDict"}

Bases a body model's own fields are complete under; any other base may contribute fields this pass does not follow.

PARAMETER_DEFAULT_LOCATION_REGEX = /\A\s*#{PARAMETER_LOCATION_REGEX}/

The same, as the whole default: x: str = Parameter(header="X"). Anchored, so a long default is not searched end to end.

PARAMETER_LOCATION_REGEX = /\bParameter\s*\((?:[^()'"]|'[^']*'|"[^"]*"|\([^()]*\))*?\b(header|cookie|query)\s*=\s*[rf]?['"]([^'"]+)['"]/

Parameter(header="X-Token") / cookie= / query=: the location and wire name, in a default or an Annotated[...] hint.

PATH_PARAM_REGEX = /\{([a-zA-Z_][a-zA-Z0-9_]*)(?::[a-zA-Z_][a-zA-Z0-9_]*)?\}/

Path param: {name} or {name:type}. Litestar uses the :type suffix as a converter (int, str, uuid, path, float); strip it when exposing the param.

PRIMITIVE_TYPE_PATTERNS = ["str", "int", "float", "bool", "bytes", "UUID", "date", "datetime"].map do |t| /\b#{t}\b/ end

classify_param runs once per typed handler parameter and rebuilt one PCRE2 pattern per primitive type on every call.

PROVIDE_KEY_RE = /['"]([A-Za-z_]\w*)['"]\s*:\s*Provide\s*\(/

Names a dependencies mapping provides ("users_service": Provide(...), or a service helper's key="users_service" inside the dependencies = ... statement): a handler parameter so named is injected, not read from the request. Keys count for handlers in the declaring file, or everywhere when that file builds the Litestar(...) app (app-level dependencies). ponytail: file scope, not Litestar's handler/controller/router scope; a same-named query param in another controller of that file is dropped too.

REQUEST_ATTR_PATTERNS = (["query_params", "path_params", "headers", "cookies"] of ::String).to_h do |attr| {attr, {/request\.#{attr}\[\s*[rf]?['"]([^'"]+)['"]\s*\]/, /request\.#{attr}\.get\(\s*[rf]?['"]([^'"]+)['"]/}} end

collect_request_attr_params runs twice per handler-body line per attribute; the attribute set is fixed, so precompile the patterns.

ROUTER_REGEX = /(#{PYTHON_VAR_NAME_REGEX})\s*=\s*Router\s*\(([^)]*)\)/m

Router(path="/prefix", route_handlers=[...])

TYPED_PATH_PARAM_REGEX = /\{([a-zA-Z_][a-zA-Z0-9_]*):[a-zA-Z_][a-zA-Z0-9_]*\}/

Class methods

tech_name
Source

Instance methods

analyze
Source
tech

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.

Source