Return a tuple in the form (app_iter, status, headers) of the application output. This works best if you pass it an application that returns an iterator all the time. Sometimes applications may use the `write()` callable returned by the `start_response` function. This tries to res
(
app: WSGIApplication, environ: WSGIEnvironment, buffered: bool = False
)
| 1224 | |
| 1225 | |
| 1226 | def run_wsgi_app( |
| 1227 | app: WSGIApplication, environ: WSGIEnvironment, buffered: bool = False |
| 1228 | ) -> tuple[t.Iterable[bytes], str, Headers]: |
| 1229 | """Return a tuple in the form (app_iter, status, headers) of the |
| 1230 | application output. This works best if you pass it an application that |
| 1231 | returns an iterator all the time. |
| 1232 | |
| 1233 | Sometimes applications may use the `write()` callable returned |
| 1234 | by the `start_response` function. This tries to resolve such edge |
| 1235 | cases automatically. But if you don't get the expected output you |
| 1236 | should set `buffered` to `True` which enforces buffering. |
| 1237 | |
| 1238 | If passed an invalid WSGI application the behavior of this function is |
| 1239 | undefined. Never pass non-conforming WSGI applications to this function. |
| 1240 | |
| 1241 | :param app: the application to execute. |
| 1242 | :param buffered: set to `True` to enforce buffering. |
| 1243 | :return: tuple in the form ``(app_iter, status, headers)`` |
| 1244 | """ |
| 1245 | # Copy environ to ensure any mutations by the app (ProxyFix, for |
| 1246 | # example) don't affect subsequent requests (such as redirects). |
| 1247 | environ = _get_environ(environ).copy() |
| 1248 | status: str |
| 1249 | response: tuple[str, list[tuple[str, str]]] | None = None |
| 1250 | buffer: list[bytes] = [] |
| 1251 | |
| 1252 | def start_response(status, headers, exc_info=None): # type: ignore |
| 1253 | nonlocal response |
| 1254 | |
| 1255 | if exc_info: |
| 1256 | try: |
| 1257 | raise exc_info[1].with_traceback(exc_info[2]) |
| 1258 | finally: |
| 1259 | exc_info = None |
| 1260 | |
| 1261 | response = (status, headers) |
| 1262 | return buffer.append |
| 1263 | |
| 1264 | app_rv = app(environ, start_response) |
| 1265 | close_func = getattr(app_rv, "close", None) |
| 1266 | app_iter: t.Iterable[bytes] = iter(app_rv) |
| 1267 | |
| 1268 | # when buffering we emit the close call early and convert the |
| 1269 | # application iterator into a regular list |
| 1270 | if buffered: |
| 1271 | try: |
| 1272 | app_iter = list(app_iter) |
| 1273 | finally: |
| 1274 | if close_func is not None: |
| 1275 | close_func() |
| 1276 | |
| 1277 | # otherwise we iterate the application iter until we have a response, chain |
| 1278 | # the already received data with the already collected data and wrap it in |
| 1279 | # a new `ClosingIterator` if we need to restore a `close` callable from the |
| 1280 | # original return value. |
| 1281 | else: |
| 1282 | for item in app_iter: |
| 1283 | buffer.append(item) |
no test coverage detected