output.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import json
  2. import logging
  3. from collections.abc import Mapping
  4. from base64 import b64encode
  5. from .framework import Global, Task
  6. from .input_ctrl import send_msg, single_input, input_control, next_event, run_async
  7. import asyncio
  8. import inspect
  9. def set_title(title):
  10. send_msg('output_ctl', dict(title=title))
  11. def text_print(text, *, ws=None):
  12. if text is None:
  13. text = ''
  14. msg = dict(command="output", spec=dict(content=text, type='text'))
  15. (ws or Global.active_ws).write_message(json.dumps(msg))
  16. def json_print(obj):
  17. text = "```\n%s\n```" % json.dumps(obj, indent=4, ensure_ascii=False)
  18. text_print(text)
  19. put_markdown = text_print
  20. def put_table(tdata, header=None):
  21. """
  22. | \| | | |
  23. | ---- | ---- | ---- | ---- |
  24. | | | | |
  25. | | | | |
  26. | | | | |
  27. :param tdata:
  28. :param header: 列表,当tdata为字典列表时,header指定表头顺序
  29. :return:
  30. """
  31. if header:
  32. tdata = [
  33. [row.get(k, '') for k in header]
  34. for row in tdata
  35. ]
  36. def quote(data):
  37. return data.replace('|', r'\|')
  38. header = "|%s|" % "|".join(map(quote, tdata[0]))
  39. res = [header]
  40. res.append("|%s|" % "|".join(['----'] * len(tdata[0])))
  41. for tr in tdata[1:]:
  42. t = "|%s|" % "|".join(map(quote, tr))
  43. res.append(t)
  44. text_print('\n'.join(res))
  45. def buttons(buttons, onclick_coro, small=False,save=None, mutex_mode=False):
  46. """
  47. :param buttons: button列表, button可用形式:
  48. {value:, label:, }
  49. (value, label,)
  50. value 单值,label等于value
  51. :param onclick_coro: CallBack(data, save) todo 允许onclick_coro非coro
  52. :param save:
  53. :param mutex_mode: 互斥模式,回调在运行过程中,无法响应同一回调
  54. :return:
  55. """
  56. btns = []
  57. for btn in buttons:
  58. if isinstance(btn, Mapping):
  59. assert 'value' in btn and 'label' in btn, 'actions item must have value and label key'
  60. elif isinstance(btn, list):
  61. assert len(btn) == 2, 'actions item format error'
  62. btn = dict(zip(('value', 'label'), btn))
  63. else:
  64. btn = dict(value=btn, label=btn)
  65. btns.append(btn)
  66. async def callback_coro():
  67. while True:
  68. event = await next_event()
  69. assert event['event'] == 'callback'
  70. coro = None
  71. if asyncio.iscoroutinefunction(onclick_coro):
  72. coro = onclick_coro(event['data'], save)
  73. elif inspect.isgeneratorfunction(onclick_coro):
  74. coro = asyncio.coroutine(onclick_coro)(save, event['data'])
  75. else:
  76. onclick_coro(event['data'], save)
  77. if coro is not None:
  78. if mutex_mode:
  79. await coro
  80. else:
  81. run_async(coro)
  82. print('Global.active_ws', Global.active_ws)
  83. callback = Task(callback_coro(), Global.active_ws)
  84. callback.coro.send(None) # 激活,Non't callback.step() ,导致嵌套调用step todo 与inactive_coro_instances整合
  85. # callback_id = callback.coro_id
  86. Global.active_ws.coros[callback.coro_id] = callback
  87. send_msg('output', dict(type='buttons', callback_id=callback.coro_id, buttons=btns, small=small))
  88. def put_file(name, content):
  89. """
  90. :param name: file name
  91. :param content: bytes-like object
  92. :return:
  93. """
  94. content = b64encode(content).decode('ascii')
  95. send_msg('output', dict(type='file', name=name, content=content))