You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

flask_utils.py 1.9KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import contextvars
  2. from collections.abc import Iterator
  3. from contextlib import contextmanager
  4. from typing import TypeVar
  5. from flask import Flask, g, has_request_context
  6. T = TypeVar("T")
  7. @contextmanager
  8. def preserve_flask_contexts(
  9. flask_app: Flask,
  10. context_vars: contextvars.Context,
  11. ) -> Iterator[None]:
  12. """
  13. A context manager that handles:
  14. 1. flask-login's UserProxy copy
  15. 2. ContextVars copy
  16. 3. flask_app.app_context()
  17. This context manager ensures that the Flask application context is properly set up,
  18. the current user is preserved across context boundaries, and any provided context variables
  19. are set within the new context.
  20. Note:
  21. This manager aims to allow use current_user cross thread and app context,
  22. but it's not the recommend use, it's better to pass user directly in parameters.
  23. Args:
  24. flask_app: The Flask application instance
  25. context_vars: contextvars.Context object containing context variables to be set in the new context
  26. Yields:
  27. None
  28. Example:
  29. ```python
  30. with preserve_flask_contexts(flask_app, context_vars=context_vars):
  31. # Code that needs Flask app context and context variables
  32. # Current user will be preserved if available
  33. ```
  34. """
  35. # Set context variables if provided
  36. if context_vars:
  37. for var, val in context_vars.items():
  38. var.set(val)
  39. # Save current user before entering new app context
  40. saved_user = None
  41. if has_request_context() and hasattr(g, "_login_user"):
  42. saved_user = g._login_user
  43. # Enter Flask app context
  44. with flask_app.app_context():
  45. try:
  46. # Restore user in new app context if it was saved
  47. if saved_user is not None:
  48. g._login_user = saved_user
  49. # Yield control back to the caller
  50. yield
  51. finally:
  52. # Any cleanup can be added here if needed
  53. pass