fastapi-reloader 1.3__py2.py3-none-any.whl → 1.3.1__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,13 @@
1
1
  from collections.abc import Awaitable, Callable
2
2
  from contextlib import asynccontextmanager
3
+ from copy import copy
3
4
  from math import inf
4
5
  from typing import TypeGuard
5
6
 
6
7
  from asgi_lifespan import LifespanManager
7
8
  from fastapi import FastAPI, Request, Response
8
9
  from fastapi.responses import StreamingResponse
10
+ from starlette.applications import Starlette
9
11
  from starlette.middleware import Middleware
10
12
  from starlette.middleware.base import BaseHTTPMiddleware
11
13
  from starlette.types import ASGIApp
@@ -14,11 +16,34 @@ from .core import reload_router
14
16
 
15
17
 
16
18
  def is_streaming_response(response: Response) -> TypeGuard[StreamingResponse]:
17
- # In fact, it may not be a fastapi's StreamingResponse, but a starlette's one with the same interface
19
+ # In fact, it may not be a Starlette's StreamingResponse, but an internal one with the same interface
18
20
  return hasattr(response, "body_iterator")
19
21
 
20
22
 
21
- def patch_for_auto_reloading(app: ASGIApp):
23
+ async def _injection_http_middleware(request: Request, call_next: Callable[[Request], Awaitable[Response]]):
24
+ res = await call_next(request)
25
+
26
+ if request.method != "GET" or "html" not in (res.headers.get("content-type", "")) or res.headers.get("content-encoding", "identity") != "identity":
27
+ return res
28
+
29
+ async def response():
30
+ if is_streaming_response(res):
31
+ async for chunk in res.body_iterator:
32
+ yield chunk
33
+ else:
34
+ yield res.body
35
+
36
+ yield b'\n\n <script src="/---fastapi-reloader---/poller.js"></script>'
37
+
38
+ headers = {k: v for k, v in res.headers.items() if k.lower() not in {"content-length", "transfer-encoding"}}
39
+
40
+ return StreamingResponse(response(), res.status_code, headers, res.media_type)
41
+
42
+
43
+ injection_middleware = Middleware(BaseHTTPMiddleware, dispatch=_injection_http_middleware)
44
+
45
+
46
+ def _reloader_middleware(app: ASGIApp):
22
47
  @asynccontextmanager
23
48
  async def lifespan(_):
24
49
  async with LifespanManager(app, inf, inf):
@@ -28,25 +53,16 @@ def patch_for_auto_reloading(app: ASGIApp):
28
53
  new_app.include_router(reload_router)
29
54
  new_app.mount("/", app)
30
55
 
31
- async def hmr_middleware(request: Request, call_next: Callable[[Request], Awaitable[Response]]):
32
- res = await call_next(request)
33
-
34
- if request.method != "GET" or "html" not in (res.headers.get("content-type", "")):
35
- return res
36
-
37
- async def response():
38
- if is_streaming_response(res):
39
- async for chunk in res.body_iterator:
40
- yield chunk
41
- else:
42
- yield res.body
43
-
44
- yield b'\n\n <script src="/---fastapi-reloader---/poller.js"></script>'
56
+ return new_app
45
57
 
46
- headers = {k: v for k, v in res.headers.items() if k.lower() not in {"content-length", "content-encoding", "transfer-encoding"}}
47
58
 
48
- return StreamingResponse(response(), res.status_code, headers, res.media_type)
59
+ def patch_for_auto_reloading(app: ASGIApp):
60
+ if isinstance(app, Starlette): # both FastAPI and Starlette have user_middleware attribute
61
+ new_app = copy(app)
62
+ new_app.user_middleware = [*app.user_middleware, injection_middleware] # before compression middlewares
63
+ return _reloader_middleware(new_app)
49
64
 
50
- new_app.user_middleware.append(Middleware(BaseHTTPMiddleware, dispatch=hmr_middleware)) # the last middleware is the first one to be called
65
+ new_app = _reloader_middleware(app)
66
+ new_app.user_middleware.append(injection_middleware) # the last middleware is the first one to be called
51
67
 
52
68
  return new_app
@@ -1,4 +1,17 @@
1
- (async function () {
1
+ async function poll() {
2
+ while (true) {
3
+ try {
4
+ const res = await fetch("/---fastapi-reloader---", { method: "HEAD" });
5
+ if (res.ok) {
6
+ break;
7
+ } else if (res.status !== 502) {
8
+ return;
9
+ }
10
+ } catch (error) {}
11
+ }
12
+ }
13
+
14
+ async function main() {
2
15
  const response = await fetch("/---fastapi-reloader---/0");
3
16
  const reader = response.body.getReader();
4
17
  const decoder = new TextDecoder();
@@ -10,20 +23,11 @@
10
23
  if (value) {
11
24
  const chunk = decoder.decode(value, { stream: true });
12
25
  if (chunk.includes("1")) {
13
- while (true) {
14
- try {
15
- const res = await fetch("/---fastapi-reloader---", {
16
- method: "HEAD",
17
- });
18
- if (res.ok) {
19
- break;
20
- } else if (res.status !== 502) {
21
- return;
22
- }
23
- } catch (error) {}
24
- }
26
+ await poll();
25
27
  location.reload();
26
28
  }
27
29
  }
28
30
  }
29
- })();
31
+ }
32
+
33
+ main();
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastapi-reloader
3
- Version: 1.3
3
+ Version: 1.3.1
4
4
  Project-URL: Homepage, https://github.com/promplate/hmr
5
5
  Requires-Dist: asgi-lifespan~=2.0
6
6
  Requires-Dist: fastapi~=0.115
@@ -0,0 +1,8 @@
1
+ fastapi_reloader-1.3.1.dist-info/METADATA,sha256=xKLO2Z0ZWciUVgTReqnzDklb611n6zA5PEthLU59ODA,2270
2
+ fastapi_reloader-1.3.1.dist-info/WHEEL,sha256=pz1FfwQ2kf9tI4G8U2ObRTKdvsTSmrreuBTtdnO8pJw,94
3
+ fastapi_reloader-1.3.1.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
+ fastapi_reloader/__init__.py,sha256=VE5m-0M92Weme8COqLs0LwIx5g6FHhqyOLGAgY6Zkzs,145
5
+ fastapi_reloader/core.py,sha256=eAyPhBZaFiKepy5NcU966adAJwqFTpHlK_uXn1cJQU8,1676
6
+ fastapi_reloader/patcher.py,sha256=nwn9sJW8KsXUr7dSPClWuPCanP453ymazfetVtuPaDA,2436
7
+ fastapi_reloader/runtime.js,sha256=pUPeMnMuKGHhBTudp6bFuNTTyZhGSvrvvWy_lWVN8nA,713
8
+ fastapi_reloader-1.3.1.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- fastapi_reloader-1.3.dist-info/METADATA,sha256=QrT6bBHmbNP3BbLMDtW7M2nskhCK_AsXgZcELTC5oCk,2268
2
- fastapi_reloader-1.3.dist-info/WHEEL,sha256=pz1FfwQ2kf9tI4G8U2ObRTKdvsTSmrreuBTtdnO8pJw,94
3
- fastapi_reloader-1.3.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
- fastapi_reloader/__init__.py,sha256=VE5m-0M92Weme8COqLs0LwIx5g6FHhqyOLGAgY6Zkzs,145
5
- fastapi_reloader/core.py,sha256=eAyPhBZaFiKepy5NcU966adAJwqFTpHlK_uXn1cJQU8,1676
6
- fastapi_reloader/patcher.py,sha256=NOLTYVkbaZxRN6BSRRbsC0gUtdxn7OdARLZppcZ12jY,1921
7
- fastapi_reloader/runtime.js,sha256=H9SCpyGpBUmfvcdlzpU4RXnIBCYSQwIqXZ7jd1bdtSo,743
8
- fastapi_reloader-1.3.dist-info/RECORD,,