Constants
ALIAS_ANNOTATION = /:\s*([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)?)\s*(?=[,)=]|$)/m
ANNOTATED_ALIAS = /^\s*(\w+)\s*(?::\s*[\w.\[\]]+\s*)?=\s*Annotated\s*\[(.+)/
CurrentUser = Annotated[User, Depends(get_current_user)], the alias the
FastAPI docs and full-stack template annotate handler parameters with.
ANNOTATED_ALIAS_DEPENDENCY = /^\s*(\w+)\s*(?::\s*[\w.\[\]]+\s*)?=\s*Annotated\s*\[.*\bDepends\s*\(\s*([\w.]+)/
AUTH_CHECKER_SUFFIX = ["checker", "check", "required", "guard", "verifier", "validator"] of ::
StringAUTH_PARAM_PATTERNS = [{/:\s*
User\s*=\s*
Depends/, "
FastAPI User dependency injection"}, {/:\s*
TokenData\s*=\s*
Depends/, "
FastAPI TokenData dependency"}, {/:\s*
HTTPAuthorizationCredentials\s*=\s*
Security/, "
FastAPI HTTP authorization"}]
Auth-related parameter type annotations
AUTHZ_FIELD = /\.(?:is_superuser|is_admin|is_staff|owner_id|roles?|permissions?|scopes)\b/
Authorization, as opposed to authentication: a role / ownership field
being read, or the handler answering 403. A dependency counts only on
the field — get_current_user raises 403 for a bad token, which is
authentication — while a route body counts on either.
ponytail: .permissions / .roles may be a data read rather than a
check; a per-statement if parse would separate them.
BARE_RETURN = /^\s*return(?:\s+None)?\s*$/
BODY_401_CHECK = "FastAPI handler 401 check"
BODY_IF = /^(el)?if\s+(.+?):\s*(raise\b.*|return\b.*)?$/
CALLER_ALIAS_PARAM = /(\w+)\s*:\s*(\w+)\s*[,)=]/
CALLER_ANNOTATED_PARAM = /(\w+)\s*:\s*Annotated\s*\[[^\n]*?\b(Depends|Security)\s*\(\s*([\w.]*)/
CALLER_PARAM = /(\w+)\s*(?::[^=,()]*(?:\[[^\]]*\][^=,()]*)?)?=\s*(Depends|Security)\s*\(\s*([\w.]*)/
CALLER_REFERENCE = /(?<![\w.])(?:request\.(?:state\.)?user\b|self\.[A-Za-z_]\w*|[A-Za-z_]\w*)/
CALLER_TERMS = /\brequest\b|\b(?:token|credentials?|authorization|subject|principal|user|anonymous|session|api_?key|headers?|cookies?)\b|is_anonymous|Anonymous/i
CALLER_WORDS = ["user", "account", "principal", "identity", "viewer", "actor", "caller"] of ::
StringName components of a dependency that hands the route its caller.
CLASS_DEF = /^(\s*)class\s+(\w+)\s*(?:\(([^)]*)\))?\s*:/
CLASS_DEPENDENCY_ATTR = /^\s*(\w+)\s*(?::[^=]+)?=\s*(?:Depends|Security)\s*\(/
DEPENDENCIES_LIST = /\bdependencies\s*=\s*\[([^\]]*)\]/m
DEPENDENCY_CALL = /\b(Depends|Security)\s*\(\s*([\w.]+)/
Any other Depends(x) / Security(x) whose callable is named for auth:
get_current_active_superuser, reusable_oauth2, verify_api_key, ...
Matched on the name's snake/camel components, never as a substring:
get_author_by_id is not auth, and get_token_count / get_roles_repo
/ permission_service fetch data rather than guard the route. The weak
words (token, role, permission) count only as the last component or before
a checker word (verify_token, check_permissions, RoleChecker).
DEPENDS_AUTH_PATTERNS = [{/
Depends\s*\(\s*get_current_user\b/, "
FastAPI Depends(get_current_user)"}, {/
Depends\s*\(\s*get_current_active_user\b/, "
FastAPI Depends(get_current_active_user)"}, {/
Depends\s*\(\s*oauth2_scheme\b/, "
FastAPI OAuth2 dependency"}, {/
Depends\s*\(\s*get_token\b/, "
FastAPI token dependency"}, {/
Depends\s*\(\s*verify_token\b/, "
FastAPI token verification"}, {/
Depends\s*\(\s*auth\b/, "
FastAPI auth dependency"}, {/
Depends\s*\(\s*require_auth\b/, "
FastAPI require_auth dependency"}, {/
Depends\s*\(\s*check_permission\b/, "
FastAPI permission check"}, {/
Depends\s*\(\s*
RoleChecker/, "
FastAPI role checker"}]
Depends() with auth-related callables
FACTORY_ITEM = /\A([A-Za-z_][\w.]*)\s*\(/
FORBIDDEN = /status_code\s*=\s*(?:403\b|status\.HTTP_403_FORBIDDEN)|\bHTTP_403_FORBIDDEN\b|HTTPException\s*\(\s*403\b/
IMPORT_FROM = /^\s*from\s+[\w.]+\s+import\s+(\([^)]*\)|[^\n]+)/m
INCLUDE_ROUTER_CALL = /^\s*([\w.]+?)\s*\.\s*include_router\s*\(/
self.app.include_router(...) is indexed too: its parent never
resolves, so that mount counts as one without a dependency.
INSTANCE_CALL = /=\s*([A-Za-z_][\w.]*)\s*\(/
LITERAL = /\A(?:True|False|None|-?\d[\d_.]*|[rbuf]?(?:"[^"]*"|'[^']*'))\z/
NAME_COMPONENT = /[A-Z]+(?![a-z])|[A-Z]?[a-z]+|\d+/
NONE_SKIPPING_TEST = /^\(?\s*(request\.(?:state\.)?user|(?:self\.)?[A-Za-z_]\w*)(?:\s+is\s+not\s+None)?\s*(?:\band\b|\)?\s*$)/
PYTHON_DEF = /^(?:async\s+)?def\s+(\w+)\s*\(/
REFUSAL_MARKER = /\b(?:401|403)\b|\bHTTP_40[13]_|Unauthori[sz]ed|Forbidden|NotAuthenticated|PermissionDenied|AuthenticationFailed/
RETURN_ANNOTATION = /\)\s*->\s*([^\n]+?)\s*:\s*$/m
RETURNED_DEPENDS = /^\s*return\s+(?:Depends|Security)\s*\(\s*(?:dependency\s*=\s*)?(\w+)\s*[,)]/
ROUTE_DECORATOR = /^\s*@(\w+)\.(?:get|post|put|patch|delete|options|head|trace|api_route|websocket)\b/
SECURITY_PATTERNS = [{/Security\s*\(\s*oauth2_scheme/, "FastAPI Security(oauth2_scheme)"}, {/Security\s*\(\s*api_key/, "FastAPI Security(api_key)"}, {/Security\s*\(\s*http_bearer/, "FastAPI Security(http_bearer)"}, {/Security\s*\(\s*http_basic/, "FastAPI Security(http_basic)"}]
SETTING_REF = /\bself\.[A-Za-z_]\w*\b(?!\s*\()/
STRONG_AUTH_WORDS = ["auth", "authn", "authz", "authenticate", "authenticated", "authentication", "authorize", "authorized", "authorization", "oauth", "jwt", "bearer", "superuser", "login", "apikey"] of ::
StringUNAUTHENTICATED_MARKER = /\b401\b|\bHTTP_401_|Unauthori[sz]ed|NotAuthenticated|AuthenticationFailed/
UNAUTHORIZED_STATUS = /status_code\s*=\s*(?:401\b|status\.HTTP_401_UNAUTHORIZED)/
WEAK_AUTH_WORDS = ["token", "tokens", "role", "roles", "permission", "permissions", "scope", "scopes"] of ::
String