-
-
Save DelgadoPanadero/dabe1d5145a1f3d482de592dbbeeffbe to your computer and use it in GitHub Desktop.
flask.g for FastAPI.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
This allows to use global variables inside the FastAPI application | |
using async mode. | |
# Usage | |
Just import `g` and then access (set/get) attributes of it: | |
```python | |
from your_project.globals import g | |
g.foo = "foo" | |
# In some other code | |
assert g.foo == "foo" | |
``` | |
Best way to utilize the global `g` in your code is to set the desired | |
value in a FastAPI dependency, like so: | |
```python | |
async def set_global_foo() -> None: | |
g.foo = "foo" | |
@app.get("/test/", dependencies=[Depends(set_global_foo)]) | |
async def test(): | |
assert g.foo == "foo" | |
``` | |
# Setup | |
Add the `GlobalsMiddleware` to your app: | |
```python | |
app = fastapi.FastAPI( | |
title="Your app API", | |
) | |
app.add_middleware(GlobalsMiddleware) # <-- This line is necessary | |
``` | |
Then just use it. ;-) | |
""" | |
from contextvars import ContextVar, Token | |
from typing import Any, Dict | |
from starlette.types import ASGIApp, Receive, Scope, Send | |
class Globals: | |
__slots__ = ("_vars", "_reset_tokens") | |
_vars: Dict[str, ContextVar] | |
_reset_tokens: Dict[str, Token] | |
def __init__(self) -> None: | |
object.__setattr__(self, '_vars', {}) | |
object.__setattr__(self, '_reset_tokens', {}) | |
def reset(self) -> None: | |
for _name, var in self._vars.items(): | |
try: | |
var.reset(self._reset_tokens[_name]) | |
# ValueError will be thrown if the reset() happens in | |
# a different context compared to the original set(). | |
# Then just set to None for this new context. | |
except ValueError: | |
var.set(None) | |
def _ensure_var(self, item: str) -> None: | |
if item not in self._vars: | |
self._vars[item] = ContextVar(f"globals:{item}", default=None) | |
self._reset_tokens[item] = self._vars[item].set(None) | |
def __getattr__(self, item: str) -> Any: | |
self._ensure_var(item) | |
return self._vars[item].get() | |
def __setattr__(self, item: str, value: Any) -> None: | |
self._ensure_var(item) | |
self._vars[item].set(value) | |
class GlobalsMiddleware: | |
def __init__(self, app: ASGIApp) -> None: | |
self.app = app | |
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: | |
g.reset() | |
await self.app(scope, receive, send) | |
g = Globals() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment