浏览代码

使用py3.5+的await语法

wangweimin 5 年之前
父节点
当前提交
1025bd43db
共有 6 个文件被更改,包括 38 次插入28 次删除
  1. 3 0
      chat_room.py
  2. 9 9
      test.py
  3. 5 5
      wsrepl/framework.py
  4. 1 1
      wsrepl/html/index.html
  5. 18 13
      wsrepl/interact.py
  6. 2 0
      wsrepl/ioloop.py

+ 3 - 0
chat_room.py

@@ -7,6 +7,8 @@ from wsrepl.ioloop import start_ioloop
 from wsrepl.interact import *
 from wsrepl.interact import *
 from tornado.gen import sleep
 from tornado.gen import sleep
 
 
+import asyncio
+
 chat_msgs = []  # 聊天记录 (name, msg)
 chat_msgs = []  # 聊天记录 (name, msg)
 
 
 
 
@@ -21,6 +23,7 @@ def refresh_msg(my_name):
 
 
 
 
 # 业务逻辑 协程
 # 业务逻辑 协程
+@asyncio.coroutine
 def main():
 def main():
     """
     """
     有返回值的交互函数需要yield from
     有返回值的交互函数需要yield from

+ 9 - 9
test.py

@@ -9,7 +9,7 @@ from tornado.gen import sleep
 
 
 
 
 # 业务逻辑 协程
 # 业务逻辑 协程
-def say_hello():
+async def say_hello():
     """
     """
     有返回值的交互函数需要yield from
     有返回值的交互函数需要yield from
     :return:
     :return:
@@ -17,35 +17,35 @@ def say_hello():
     set_title("This is title")
     set_title("This is title")
     # 向用户输出文字
     # 向用户输出文字
     text_print("Welcome!!!")
     text_print("Welcome!!!")
-    res = yield from actions('Action button', [
+    res = await actions('Action button', [
         {'value': '1', 'label': 'One', 'disabled': False},
         {'value': '1', 'label': 'One', 'disabled': False},
         {'value': '2', 'label': 'Two', 'disabled': False},
         {'value': '2', 'label': 'Two', 'disabled': False},
         {'value': '3', 'label': 'Three', 'disabled': True},
         {'value': '3', 'label': 'Three', 'disabled': True},
     ])
     ])
     text_print('Your input:%s' % res)
     text_print('Your input:%s' % res)
 
 
-    res = yield from select('This is select input', [
+    res = await select('This is select input', [
         {'value': 1, 'label': 'one', 'selected': False, 'disabled': False},
         {'value': 1, 'label': 'one', 'selected': False, 'disabled': False},
         {'value': 2, 'label': 'two', 'selected': True, 'disabled': False},
         {'value': 2, 'label': 'two', 'selected': True, 'disabled': False},
         {'value': 2, 'label': 'three disabled', 'selected': False, 'disabled': True},
         {'value': 2, 'label': 'three disabled', 'selected': False, 'disabled': True},
     ], type=SELECT, multiple=False)
     ], type=SELECT, multiple=False)
     text_print('Your input:%s' % res)
     text_print('Your input:%s' % res)
 
 
-    res = yield from select('This is multiple select input', [
+    res = await select('This is multiple select input', [
         {'value': 1, 'label': 'one', 'selected': True, 'disabled': False},
         {'value': 1, 'label': 'one', 'selected': True, 'disabled': False},
         {'value': 2, 'label': 'two', 'selected': True, 'disabled': False},
         {'value': 2, 'label': 'two', 'selected': True, 'disabled': False},
         {'value': 2, 'label': 'three disabled', 'selected': False, 'disabled': True},
         {'value': 2, 'label': 'three disabled', 'selected': False, 'disabled': True},
     ], type=SELECT, multiple=True)
     ], type=SELECT, multiple=True)
     text_print('Your input:%s' % res)
     text_print('Your input:%s' % res)
 
 
-    res = yield from select('This is RADIO input', [
+    res = await select('This is RADIO input', [
         {'value': 1, 'label': 'one', 'selected': False, 'disabled': False},
         {'value': 1, 'label': 'one', 'selected': False, 'disabled': False},
         {'value': 2, 'label': 'two', 'selected': True, 'disabled': False},
         {'value': 2, 'label': 'two', 'selected': True, 'disabled': False},
         {'value': 2, 'label': 'three disabled', 'selected': False, 'disabled': True},
         {'value': 2, 'label': 'three disabled', 'selected': False, 'disabled': True},
     ], type=RADIO)
     ], type=RADIO)
     text_print('Your input:%s' % res)
     text_print('Your input:%s' % res)
 
 
-    res = yield from select('This is CHECKBOX input', [
+    res = await select('This is CHECKBOX input', [
         {'value': 1, 'label': 'one', 'selected': False, 'disabled': False},
         {'value': 1, 'label': 'one', 'selected': False, 'disabled': False},
         {'value': 2, 'label': 'two', 'selected': True, 'disabled': False},
         {'value': 2, 'label': 'two', 'selected': True, 'disabled': False},
         {'value': 2, 'label': 'three disabled', 'selected': False, 'disabled': True},
         {'value': 2, 'label': 'three disabled', 'selected': False, 'disabled': True},
@@ -53,13 +53,13 @@ def say_hello():
 
 
     text_print('Your input:%s' % res)
     text_print('Your input:%s' % res)
 
 
-    res = yield from input('This is single input')
+    res = await input('This is single input')
     text_print('Your input:%s' % res)
     text_print('Your input:%s' % res)
 
 
-    res = yield from input('This is another single input')
+    res = await input('This is another single input')
     text_print('Your input:%s' % res)
     text_print('Your input:%s' % res)
 
 
-    res = yield from input_group('Group input', [
+    res = await input_group('Group input', [
         input('Input 1', name='one'),
         input('Input 1', name='one'),
         input('Input 2', name='two'),
         input('Input 2', name='two'),
         select('Input 2', options=['A', 'B', 'C'], type=CHECKBOX, name='three')
         select('Input 2', options=['A', 'B', 'C'], type=CHECKBOX, name='three')

+ 5 - 5
wsrepl/framework.py

@@ -6,10 +6,10 @@ import random, string
 from contextlib import contextmanager
 from contextlib import contextmanager
 from tornado.log import gen_log
 from tornado.log import gen_log
 from tornado import ioloop
 from tornado import ioloop
-from tornado.concurrent import Future
+# from tornado.concurrent import Future
 
 
 
 
-class Future_:
+class WebIOFuture:
     def __iter__(self):
     def __iter__(self):
         result = yield
         result = yield
         return result
         return result
@@ -58,7 +58,7 @@ class Task:
         try:
         try:
             with self.ws_context():
             with self.ws_context():
                 future_or_none = self.coro.send(result)
                 future_or_none = self.coro.send(result)
-            if future_or_none is not None:
+            if not isinstance(future_or_none, WebIOFuture) and future_or_none is not None:
                 if not self.ws.closed():
                 if not self.ws.closed():
                     future_or_none.add_done_callback(self._tornado_future_callback)
                     future_or_none.add_done_callback(self._tornado_future_callback)
                     self.pending_futures[id(future_or_none)] = future_or_none
                     self.pending_futures[id(future_or_none)] = future_or_none
@@ -70,7 +70,7 @@ class Task:
 
 
             gen_log.debug('Task[%s] finished, self.coros:%s', self.coro_id, self.ws.coros)
             gen_log.debug('Task[%s] finished, self.coros:%s', self.coro_id, self.ws.coros)
 
 
-    def _tornado_future_callback(self, future: Future):
+    def _tornado_future_callback(self, future):
         del self.pending_futures[id(future)]
         del self.pending_futures[id(future)]
         self.step(future.result())
         self.step(future.result())
 
 
@@ -113,5 +113,5 @@ class Msg:
 
 
 class Global:
 class Global:
     # todo issue: with 语句可能发生嵌套,导致内层with退出时,将属性置空
     # todo issue: with 语句可能发生嵌套,导致内层with退出时,将属性置空
-    active_ws: "EchoWebSocket" = None
+    active_ws = None  # type:"EchoWebSocket"
     active_coro_id = None
     active_coro_id = None

+ 1 - 1
wsrepl/html/index.html

@@ -73,7 +73,7 @@
 <script>
 <script>
     var md_body = $('#markdown-body');
     var md_body = $('#markdown-body');
 
 
-    var ws = new WebSocket("ws://localhost:8080/test");
+    var ws = new WebSocket("ws://"+window.location.host+"/test");
 
 
     var ctrl = new WSREPL.WSREPLController(ws, md_body, $('#input-container'));
     var ctrl = new WSREPL.WSREPLController(ws, md_body, $('#input-container'));
 
 

+ 18 - 13
wsrepl/interact.py

@@ -1,7 +1,7 @@
 import tornado.websocket
 import tornado.websocket
 import time, json
 import time, json
 from collections import defaultdict
 from collections import defaultdict
-from .framework import Future, Msg, Global
+from .framework import WebIOFuture, Msg, Global
 from collections.abc import Iterable, Mapping, Sequence
 from collections.abc import Iterable, Mapping, Sequence
 
 
 import logging
 import logging
@@ -20,10 +20,15 @@ def send_msg(cmd, spec=None):
 
 
 def get_response(cmd, spec):
 def get_response(cmd, spec):
     send_msg(cmd, spec)
     send_msg(cmd, spec)
-    response_msg = yield from Future()
+    response_msg = yield from WebIOFuture()
     return response_msg
     return response_msg
 
 
 
 
+async def next_event():
+    res = await WebIOFuture()
+    return res
+
+
 TEXT = 'text'
 TEXT = 'text'
 NUMBER = "number"
 NUMBER = "number"
 PASSWORD = "password"
 PASSWORD = "password"
@@ -32,7 +37,7 @@ RADIO = 'radio'
 SELECT = 'select'
 SELECT = 'select'
 
 
 
 
-def _input_event_handle(valid_funcs, whole_valid_func=None):
+async def _input_event_handle(valid_funcs, whole_valid_func=None):
     """
     """
     根据提供的校验函数处理表单事件
     根据提供的校验函数处理表单事件
     :param valid_funcs: map(name -> valid_func)  valid_func 为 None 时,不进行验证
     :param valid_funcs: map(name -> valid_func)  valid_func 为 None 时,不进行验证
@@ -41,7 +46,7 @@ def _input_event_handle(valid_funcs, whole_valid_func=None):
     :return:
     :return:
     """
     """
     while True:
     while True:
-        event = yield
+        event = await next_event()
         event_name, event_data = event['event'], event['data']
         event_name, event_data = event['event'], event['data']
         if event_name == 'input_event':
         if event_name == 'input_event':
             input_event = event_data['event_name']
             input_event = event_data['event_name']
@@ -144,7 +149,7 @@ def _make_input_spec(label, type, name, valid_func=None, multiple=None, inline=N
     return input_item
     return input_item
 
 
 
 
-def input(label, type=TEXT, *, valid_func=None, name='data', value='', placeholder='', required=None, readonly=None,
+async def input(label, type=TEXT, *, valid_func=None, name='data', value='', placeholder='', required=None, readonly=None,
           disabled=None, **other_html_attrs):
           disabled=None, **other_html_attrs):
     input_kwargs = dict(locals())
     input_kwargs = dict(locals())
     input_kwargs['label'] = ''
     input_kwargs['label'] = ''
@@ -155,11 +160,11 @@ def input(label, type=TEXT, *, valid_func=None, name='data', value='', placehold
     allowed_type = {TEXT, NUMBER, PASSWORD}
     allowed_type = {TEXT, NUMBER, PASSWORD}
     assert type in allowed_type, 'Input type not allowed.'
     assert type in allowed_type, 'Input type not allowed.'
 
 
-    data = yield from input_group(label=label, inputs=[input_kwargs])
+    data = await input_group(label=label, inputs=[input_kwargs])
     return data[name]
     return data[name]
 
 
 
 
-def select(label, options, type=SELECT, *, multiple=None, valid_func=None, name='data', value='', placeholder='',
+async def select(label, options, type=SELECT, *, multiple=None, valid_func=None, name='data', value='', placeholder='',
            required=None, readonly=None, disabled=None, inline=None, **other_html_attrs):
            required=None, readonly=None, disabled=None, inline=None, **other_html_attrs):
     """
     """
     参数值为None表示不指定,使用默认值
     参数值为None表示不指定,使用默认值
@@ -192,7 +197,7 @@ def select(label, options, type=SELECT, *, multiple=None, valid_func=None, name=
     allowed_type = {CHECKBOX, RADIO, SELECT}
     allowed_type = {CHECKBOX, RADIO, SELECT}
     assert type in allowed_type, 'Input type not allowed.'
     assert type in allowed_type, 'Input type not allowed.'
 
 
-    data = yield from input_group(label=label, inputs=[input_kwargs])
+    data = await input_group(label=label, inputs=[input_kwargs])
     return data[name]
     return data[name]
 
 
 
 
@@ -221,7 +226,7 @@ def _make_actions_input_spec(label, buttons, name):
     return input_item
     return input_item
 
 
 
 
-def actions(label, buttons, name='data'):
+async def actions(label, buttons, name='data'):
     """
     """
     选择一个动作。UI为多个按钮,点击后会将整个表单提交
     选择一个动作。UI为多个按钮,点击后会将整个表单提交
     :param label:
     :param label:
@@ -240,11 +245,11 @@ def actions(label, buttons, name='data'):
     """
     """
     input_kwargs = dict(label='', buttons=buttons, name=name)
     input_kwargs = dict(label='', buttons=buttons, name=name)
     input_kwargs['__name__'] = actions.__name__
     input_kwargs['__name__'] = actions.__name__
-    data = yield from input_group(label=label, inputs=[input_kwargs])
+    data = await input_group(label=label, inputs=[input_kwargs])
     return data[name]
     return data[name]
 
 
 
 
-def input_group(label, inputs, valid_func=None):
+async def input_group(label, inputs, valid_func=None):
     """
     """
     :param label:
     :param label:
     :param inputs: list of generator or dict, dict的话,需要多加一项 __name__ 为当前函数名
     :param inputs: list of generator or dict, dict的话,需要多加一项 __name__ 为当前函数名
@@ -264,7 +269,7 @@ def input_group(label, inputs, valid_func=None):
             func_name = input_g.pop('__name__')
             func_name = input_g.pop('__name__')
             input_kwargs = input_g
             input_kwargs = input_g
         else:
         else:
-            input_kwargs = dict(input_g.gi_frame.f_locals)  # 拷贝一份,不可以对locals进行修改
+            input_kwargs = dict(input_g.cr_frame.f_locals)  # 拷贝一份,不可以对locals进行修改
             func_name = input_g.__name__
             func_name = input_g.__name__
 
 
         input_name = input_kwargs['name']
         input_name = input_kwargs['name']
@@ -280,7 +285,7 @@ def input_group(label, inputs, valid_func=None):
                 break
                 break
 
 
     send_msg('input_group', dict(label=label, inputs=spec_inputs))
     send_msg('input_group', dict(label=label, inputs=spec_inputs))
-    data = yield from _input_event_handle(item_valid_funcs, valid_func)
+    data = await _input_event_handle(item_valid_funcs, valid_func)
     send_msg('destroy_form')
     send_msg('destroy_form')
     return data
     return data
 
 

+ 2 - 0
wsrepl/ioloop.py

@@ -54,6 +54,8 @@ def start_ioloop(coro_func, port=8080):
                     del self.coros[task.coro_id]
                     del self.coros[task.coro_id]
 
 
             if self.main_task.task_finished:
             if self.main_task.task_finished:
+                for t in self.coros:
+                    t.cancel()
                 self.close()
                 self.close()
 
 
         def on_message(self, message):
         def on_message(self, message):