Coverage for archdocs/features/http_api/parser.py: 100%
14 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-18 22:03 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-18 22:03 +0000
1import re as py_re
2import typing
4from archdocs import prefilter, settings
5from archdocs.features.http_api.const import HTTPApiFeatures
8# A route decorator is called with a path literal (possibly empty, possibly an f-string, with
9# leading `{...}` expressions allowed) or with nothing at all: anything looser counts
10# `@mock.patch("src.payments")` in a test file that also imports a TestClient as REST traffic.
11# Paths passed as `path=` keywords slip away — that trade is taken knowingly.
12_SERVED_METHOD_PATTERN: typing.Final = py_re.compile(
13 r"@(?:\w+\.)?(post|put|patch|delete|get|head|options|trace)\s*\(\s*"
14 r"(?:\)|[frbu]{0,2}[\"'](?:\{[^}\"']*\})*(?:/|[\"']))",
15 flags=settings.TYPICAL_RE_FLAGS,
16)
17# A decorated method alone says nothing — every router library spells them the same way — so the
18# framework has to be imported in the very file the route is written in.
19_FRAMEWORK_IMPORT_PATTERN: typing.Final = py_re.compile(
20 r"\b(?:from|import)\s+(?:fastapi|litestar)\b",
21 flags=settings.TYPICAL_RE_FLAGS,
22)
23_FRAMEWORK_LITERALS: typing.Final = ("fastapi", "litestar")
24_EMPTY_FEATURES: typing.Final = HTTPApiFeatures(served_methods=frozenset())
27def find_fastapi_and_litestar_features(raw_source: str) -> HTTPApiFeatures:
28 if not prefilter.contains_any_literal(raw_source.lower(), _FRAMEWORK_LITERALS):
29 return _EMPTY_FEATURES
30 if not _FRAMEWORK_IMPORT_PATTERN.search(raw_source):
31 return _EMPTY_FEATURES
32 return HTTPApiFeatures(served_methods=frozenset(_SERVED_METHOD_PATTERN.findall(raw_source)))