Skip to content

Instantly share code, notes, and snippets.

@DelgadoPanadero
Forked from ddanier/fastapi_globals.py
Created August 24, 2022 17:54
Show Gist options
  • Save DelgadoPanadero/dabe1d5145a1f3d482de592dbbeeffbe to your computer and use it in GitHub Desktop.
Save DelgadoPanadero/dabe1d5145a1f3d482de592dbbeeffbe to your computer and use it in GitHub Desktop.
flask.g for FastAPI.
"""
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