context.py 2.1 KB

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