context.py 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. # (c) Nelen & Schuurmans
  2. import os
  3. from contextvars import ContextVar
  4. from typing import FrozenSet
  5. from typing import Optional
  6. from pydantic import AnyUrl
  7. from pydantic import FileUrl
  8. from .value_object import ValueObject
  9. __all__ = ["ctx", "User", "Tenant", "Scope"]
  10. class User(ValueObject):
  11. id: str
  12. name: str
  13. Scope = FrozenSet[str]
  14. class Tenant(ValueObject):
  15. id: int
  16. name: str
  17. class Context:
  18. """Provide global access to some contextual properties.
  19. The implementation makes use of python's contextvars, which automatically integrates
  20. with asyncio tasks (so that each task runs in its own context). This makes sure that
  21. every request-response cycle is isolated.
  22. """
  23. def __init__(self):
  24. self._path_value: ContextVar[AnyUrl] = ContextVar(
  25. "path_value",
  26. default=FileUrl.build(scheme="file", host="/", path=os.getcwd()),
  27. )
  28. self._user_value: ContextVar[User] = ContextVar(
  29. "user_value", default=User(id="ANONYMOUS", name="anonymous")
  30. )
  31. self._tenant_value: ContextVar[Optional[Tenant]] = ContextVar(
  32. "tenant_value", default=None
  33. )
  34. @property
  35. def path(self) -> AnyUrl:
  36. return self._path_value.get()
  37. @path.setter
  38. def path(self, value: AnyUrl) -> None:
  39. self._path_value.set(value)
  40. @property
  41. def user(self) -> User:
  42. return self._user_value.get()
  43. @user.setter
  44. def user(self, value: User) -> None:
  45. self._user_value.set(value)
  46. @property
  47. def tenant(self) -> Optional[Tenant]:
  48. return self._tenant_value.get()
  49. @tenant.setter
  50. def tenant(self, value: Optional[Tenant]) -> None:
  51. self._tenant_value.set(value)
  52. ctx = Context()