__init__.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import threading, asyncio, inspect
  2. from functools import wraps
  3. from .base import AbstractSession
  4. from .coroutinebased import CoroutineBasedSession
  5. from .threadbased import ThreadBasedSession, ScriptModeSession
  6. from ..exceptions import SessionNotFoundException
  7. THREAD_BASED = 'ThreadBased'
  8. COROUTINE_BASED = 'CoroutineBased'
  9. _session_type = ThreadBasedSession
  10. __all__ = ['run_async', 'run_asyncio_coroutine', 'register_thread', 'THREAD_BASED', 'COROUTINE_BASED']
  11. _server_started = False
  12. def mark_server_started(session_type_name=None):
  13. """标记服务端已经启动. 仅用于PyWebIO内部使用"""
  14. global _server_started
  15. _server_started = True
  16. if session_type_name is not None:
  17. _set_session_implement(session_type_name)
  18. def get_session_implement_for_target(target_func):
  19. """根据target_func函数类型获取默认会话实现"""
  20. if asyncio.iscoroutinefunction(target_func) or inspect.isgeneratorfunction(target_func):
  21. return COROUTINE_BASED
  22. return THREAD_BASED
  23. def _set_session_implement(session_type_name):
  24. """设置会话实现类. 仅用于PyWebIO内部使用"""
  25. global _session_type
  26. sessions = {THREAD_BASED: ThreadBasedSession, COROUTINE_BASED: CoroutineBasedSession}
  27. assert session_type_name in sessions, ValueError('No "%s" Session type ' % session_type_name)
  28. _session_type = sessions[session_type_name]
  29. def get_session_implement():
  30. global _session_type
  31. return _session_type
  32. def _start_script_mode_server():
  33. global _session_type
  34. from ..platform import start_server_in_current_thread_session
  35. _session_type = ScriptModeSession
  36. start_server_in_current_thread_session()
  37. def get_current_session() -> "AbstractSession":
  38. try:
  39. return _session_type.get_current_session()
  40. except SessionNotFoundException:
  41. if _server_started:
  42. raise
  43. # 没有显式启动backend server时,在当前线程上下文作为session启动backend server
  44. _start_script_mode_server()
  45. return _session_type.get_current_session()
  46. def get_current_task_id():
  47. try:
  48. return _session_type.get_current_task_id()
  49. except RuntimeError:
  50. if _server_started:
  51. raise
  52. # 没有显式启动backend server时,在当前线程上下文作为session启动backend server
  53. _start_script_mode_server()
  54. return _session_type.get_current_task_id()
  55. def check_session_impl(session_type):
  56. def decorator(func):
  57. @wraps(func)
  58. def inner(*args, **kwargs):
  59. now_impl = get_session_implement()
  60. if not issubclass(now_impl,
  61. session_type): # Check if 'now_impl' is a derived from session_type or is the same class
  62. func_name = getattr(func, '__name__', str(func))
  63. require = getattr(session_type, '__name__', str(session_type))
  64. now = getattr(now_impl, '__name__', str(now_impl))
  65. raise RuntimeError("Only can invoke `{func_name:s}` in {require:s} context."
  66. " You are now in {now:s} context".format(func_name=func_name, require=require,
  67. now=now))
  68. return func(*args, **kwargs)
  69. return inner
  70. return decorator
  71. @check_session_impl(CoroutineBasedSession)
  72. def run_async(coro_obj):
  73. """异步运行协程对象。协程中依然可以调用 PyWebIO 交互函数。 仅能在 CoroutineBasedSession 会话上下文中调用
  74. :param coro_obj: 协程对象
  75. :return: An instance of `TaskHandle <pywebio.session.coroutinebased.TaskHandle>` is returned, which can be used later to close the task.
  76. """
  77. return get_current_session().run_async(coro_obj)
  78. @check_session_impl(CoroutineBasedSession)
  79. async def run_asyncio_coroutine(coro_obj):
  80. """若会话线程和运行事件的线程不是同一个线程,需要用 run_asyncio_coroutine 来运行asyncio中的协程
  81. :param coro_obj: 协程对象
  82. """
  83. return await get_current_session().run_asyncio_coroutine(coro_obj)
  84. @check_session_impl(ThreadBasedSession)
  85. def register_thread(thread: threading.Thread):
  86. """注册线程,以便在线程内调用 PyWebIO 交互函数。仅能在 ThreadBasedSession 会话上下文中调用
  87. :param threading.Thread thread: 线程对象
  88. """
  89. return get_current_session().register_thread(thread)