예제 #1
0
파일: tests.py 프로젝트: zjjott/html
        def mock_fetch(request, callback=None, raise_error=True, **kwargs):
            """mock 掉RESTfulAsyncClient的fetch函数,使之不再发起向外请求
            并且响应始终是固定的
            """
            future = TracebackFuture()
            if callback is not None:

                def handle_future(future):
                    """future的回调,单元测试里一般会挂上self.top"""
                    response = future.result()
                    self.io_loop.add_callback(callback, response)

                future.add_done_callback(handle_future)

            def immediately_done():
                """立即完成future"""
                buf = StringIO()
                buf.write(
                    json.dumps({  # 思索。。这里好像只能写死,要传参的话得在_request上再打一层
                        "ok": True,
                        "mock": True,
                        'user': {
                            "id": "1",
                            "username": "******",
                        }
                    }))
                response = HTTPResponse(request, 200, buffer=buf)
                future.set_result(response)

            self.io_loop.add_callback(immediately_done)
            return future
예제 #2
0
파일: test_gen.py 프로젝트: zhaosir/Demo
    def wrapper(*args, **kwargs):
        future = TracebackFuture()
#        ipdb.set_trace()
        print args, kwargs
#        callback, args, kwargs = replacer.replace(lambda value=_NO_RESULT: future.set_result(value),args, kwargs)
        callback = None
        kwargs['callback'] = lambda value = _NO_RESULT: future.set_result(value)
        print callback, args, kwargs
        def handle_error(typ, value, tb):
            future.set_exc_info((typ, value, tb))
            return True

        exc_info = None
        with ExceptionStackContext(handle_error):
            try:
                result = f(*args, **kwargs)
                if result is not None:
                    raise ReturnValueIgnoredError('@return_future should not be used with function that return values')
            except:
                exc_info = sys.exc_info()
                raise

        if exc_info is not None:
            future.result()

        if callback is not None:
            def run_callback(future):
                result = future.result()
                if result is _NO_RESULT:
                    callback('result is NULL')
                else:
                    callback(future.result())
            future.add_done_callback(wrap(run_callback))
#        print future.result(), 'in the wapper'
        return future
예제 #3
0
    def fetch(self, request, callback=None, **kwargs):
        """Executes a request, asynchronously returning an `HTTPResponse`.

        The request may be either a string URL or an `HTTPRequest` object.
        If it is a string, we construct an `HTTPRequest` using any additional
        kwargs: ``HTTPRequest(request, **kwargs)``

        # 注意,任何状态码不是200的都会抛出异常,需要自己捕获或者添加一个callback函数
        This method returns a `.Future` whose result is an
        `HTTPResponse`.  The ``Future`` will raise an `HTTPError` if
        the request returned a non-200 response code.

        如果添加了callback,那么不会有一个自动抛出的异常
        If a ``callback`` is given, it will be invoked with the `HTTPResponse`.
        In the callback interface, `HTTPError` is not automatically raised.
        Instead, you must check the response's ``error`` attribute or
        call its `~HTTPResponse.rethrow` method.
        """
        if not isinstance(request, HTTPRequest):
            request = HTTPRequest(url=request, **kwargs)
        # We may modify this (to add Host, Accept-Encoding, etc),
        # so make sure we don't modify the caller's object.  This is also
        # where normal dicts get converted to HTTPHeaders objects.
        # 构建headers,封装的一个类,处理起来比较方便
        request.headers = httputil.HTTPHeaders(request.headers)

        # request.request, request.defaults
        request = _RequestProxy(request, self.defaults)
        future = TracebackFuture()

        # 这个callback先放过
        if callback is not None:
            callback = stack_context.wrap(callback)

            def handle_future(future):
                exc = future.exception()
                if isinstance(exc, HTTPError) and exc.response is not None:
                    response = exc.response
                elif exc is not None:
                    response = HTTPResponse(
                        request, 599, error=exc,
                        request_time=time.time() - request.start_time)
                else:
                    response = future.result()
                self.io_loop.add_callback(callback, response)
            future.add_done_callback(handle_future)

        def handle_response(response):
            if response.error:
                future.set_exception(response.error)
            else:
                future.set_result(response)
        # rquest异步成功之后执行 handle_response(response)
        self.fetch_impl(request, handle_response)

        # 返回一个future类型
        return future
예제 #4
0
    def fetch(self, request, callback=None, raise_error=True, **kwargs):
        """Executes a request, asynchronously returning an `HTTPResponse`.

        The request may be either a string URL or an `HTTPRequest` object.
        If it is a string, we construct an `HTTPRequest` using any additional
        kwargs: ``HTTPRequest(request, **kwargs)``

        This method returns a `.Future` whose result is an
        `HTTPResponse`. By default, the ``Future`` will raise an
        `HTTPError` if the request returned a non-200 response code
        (other errors may also be raised if the server could not be
        contacted). Instead, if ``raise_error`` is set to False, the
        response will always be returned regardless of the response
        code.

        If a ``callback`` is given, it will be invoked with the `HTTPResponse`.
        In the callback interface, `HTTPError` is not automatically raised.
        Instead, you must check the response's ``error`` attribute or
        call its `~HTTPResponse.rethrow` method.
        """
        if self._closed:
            raise RuntimeError("fetch() called on closed AsyncHTTPClient")
        if not isinstance(request, HTTPRequest):
            request = HTTPRequest(url=request, **kwargs)
        # We may modify this (to add Host, Accept-Encoding, etc),
        # so make sure we don't modify the caller's object.  This is also
        # where normal dicts get converted to HTTPHeaders objects.
        request.headers = httputil.HTTPHeaders(request.headers)
        request = _RequestProxy(request, self.defaults)
        future = TracebackFuture()
        if callback is not None:
            callback = stack_context.wrap(callback)

            def handle_future(future):
                exc = future.exception()
                if isinstance(exc, HTTPError) and exc.response is not None:
                    response = exc.response
                elif exc is not None:
                    response = HTTPResponse(request,
                                            599,
                                            error=exc,
                                            request_time=time.time() -
                                            request.start_time)
                else:
                    response = future.result()
                self.io_loop.add_callback(callback, response)

            future.add_done_callback(handle_future)

        def handle_response(response):
            if raise_error and response.error:
                future.set_exception(response.error)
            else:
                future.set_result(response)

        self.fetch_impl(request, handle_response)
        return future
예제 #5
0
    def fetch(self, request, callback=None, raise_error=True, **kwargs):
        """Executes a request, asynchronously returning an `HTTPResponse`.

        The request may be either a string URL or an `HTTPRequest` object.
        If it is a string, we construct an `HTTPRequest` using any additional
        kwargs: ``HTTPRequest(request, **kwargs)``

        This method returns a `.Future` whose result is an
        `HTTPResponse`. By default, the ``Future`` will raise an
        `HTTPError` if the request returned a non-200 response code
        (other errors may also be raised if the server could not be
        contacted). Instead, if ``raise_error`` is set to False, the
        response will always be returned regardless of the response
        code.

        If a ``callback`` is given, it will be invoked with the `HTTPResponse`.
        In the callback interface, `HTTPError` is not automatically raised.
        Instead, you must check the response's ``error`` attribute or
        call its `~HTTPResponse.rethrow` method.
        """
        if self._closed:
            raise RuntimeError("fetch() called on closed AsyncHTTPClient")
        if not isinstance(request, HTTPRequest):
            request = HTTPRequest(url=request, **kwargs)
        else:
            if kwargs:
                raise ValueError("kwargs can't be used if request is an HTTPRequest object")
        # We may modify this (to add Host, Accept-Encoding, etc),
        # so make sure we don't modify the caller's object.  This is also
        # where normal dicts get converted to HTTPHeaders objects.
        request.headers = httputil.HTTPHeaders(request.headers)
        request = _RequestProxy(request, self.defaults)
        future = TracebackFuture()
        if callback is not None:
            callback = stack_context.wrap(callback)

            def handle_future(future):
                exc = future.exception()
                if isinstance(exc, HTTPError) and exc.response is not None:
                    response = exc.response
                elif exc is not None:
                    response = HTTPResponse(
                        request, 599, error=exc,
                        request_time=time.time() - request.start_time)
                else:
                    response = future.result()
                self.io_loop.add_callback(callback, response)
            future.add_done_callback(handle_future)

        def handle_response(response):
            if raise_error and response.error:
                future.set_exception(response.error)
            else:
                future.set_result(response)
        self.fetch_impl(request, handle_response)
        return future
예제 #6
0
파일: rpc.py 프로젝트: ethaniz/torpc
 def register(self, name, callback=None):
     msg_id = next(self._generator)
     request = packer.dumps(('register', name))
     buff = struct.pack('!ibi', len(request), RPC_REGISTER, msg_id) + request
     future = TracebackFuture()
     if callback:
         future.add_done_callback(callback)
     self.add_request_table(msg_id, future)
     self.write(buff)
     return future
예제 #7
0
 def close(self):
     if self._cursor is None:
         future = TracebackFuture()
         future.set_result(None)
         return future
     future = async_call_method(self._cursor.close)
     def do_close(future):
         self._cursor = None
     future.add_done_callback(do_close)
     return future
예제 #8
0
파일: client.py 프로젝트: astwyg/ct-fcore
    def fetch(self, url, headers=None, body=None, method="GET", callback=None, raise_error=True, cache=None, **kwargs):
        headers = headers or {}
        body = body or "{}"
        """very simlar with AsyncHTTPClient.fetch
        """
        if self._closed:
            raise RuntimeError("fetch() called on closed AsyncHTTPClient")
        future = TracebackFuture()
        if isinstance(body, dict):
            for k,v in body.items():
                if v is None:
                    del body[k]
            body = urllib.urlencode(body)
        for k,v in headers.items(): #headers 只能接收str
            if v:
                headers[k] = str(headers[k])
            else:
                del headers[k]
        request = HTTPRequest(url=url,method=method,headers=headers,body=body, allow_nonstandard_methods=True, request_timeout=600 ,**kwargs)
        # We may modify this (to add Host, Accept-Encoding, etc),
        # so make sure we don't modify the caller's object.  This is also
        # where normal dicts get converted to HTTPHeaders objects.
        request.headers = httputil.HTTPHeaders(request.headers)
        request = _RequestProxy(request, self.defaults)
        if callback is not None:
            callback = stack_context.wrap(callback)

            def handle_future(future):
                exc = future.exception()
                if isinstance(exc, HTTPError) and exc.response is not None:
                    response = exc.response
                elif exc is not None:
                    response = HTTPResponse(
                        request, 599, error=exc,
                        request_time=time.time() - request.start_time)
                else:
                    response = future.result()
                self.io_loop.add_callback(callback, response)
            future.add_done_callback(handle_future)

        def handle_response(response):
            if raise_error and response.error:
                future.set_exception(response.error)
            else:
                try:
                    resp = json.loads(str(response.body))
                    if resp.get("statusCode") and resp.get("statusCode")==800:
                        future.set_result(resp)
                        log.info(json.dumps({"response":resp,"body":body,"headers":headers,"url":url}))
                    else:
                        future.set_result({"error_type":"statusCode is not 800", "response":resp,"body":body,"headers":headers,"url":url})
                        log.error(json.dumps({"error_type":"statusCode is not 800", "response":resp,"body":body,"headers":headers,"url":url}))
                except Exception,e:
                    future.set_result({"error_type":"json.loads failed!","error":str(e),"response.body":response.body,"body":body,"headers":headers,"url":url})
                    log.error(json.dumps({"error_type":"json.loads failed!","error":str(e),"response.body":response.body,"body":body,"headers":headers,"url":url}))
예제 #9
0
    def fetch(self, request, callback=None, raise_error=True, **kwargs):
        """执行一个请求, 并且异步的返回 `HTTPResponse`.

        request 参数可以是一个 URL 字符串也可以是一个 `HTTPRequest` 对象.
        如果是一个字符串, 我们将使用全部的关键字参数一起构造一个
        `HTTPRequest` 对象: ``HTTPRequest(request, **kwargs)``

        这个方法返回一个结果为 `HTTPResponse` 的 `.Future` 对象.
        默认情况下, 如果该请求返回一个非 200 的响应码, 这个 ``Future``
        将会抛出一个 `HTTPError` 错误. 相反, 如果 ``raise_error`` 设置为
        False, 则无论响应码如何, 都将返回该 response (响应).

        如果给定了 ``callback`` , 它将被 `HTTPResponse` 调用.
        在回调接口中, `HTTPError` 不会自动抛出. 相反你必须检查该响应的
        ``error`` 属性或者调用它的 `~HTTPResponse.rethrow` 方法.
        """
        if self._closed:
            raise RuntimeError("fetch() called on closed AsyncHTTPClient")
        if not isinstance(request, HTTPRequest):
            request = HTTPRequest(url=request, **kwargs)
        # We may modify this (to add Host, Accept-Encoding, etc),
        # so make sure we don't modify the caller's object.  This is also
        # where normal dicts get converted to HTTPHeaders objects.
        request.headers = httputil.HTTPHeaders(request.headers)
        request = _RequestProxy(request, self.defaults)
        future = TracebackFuture()
        if callback is not None:
            callback = stack_context.wrap(callback)

            def handle_future(future):
                exc = future.exception()
                if isinstance(exc, HTTPError) and exc.response is not None:
                    response = exc.response
                elif exc is not None:
                    response = HTTPResponse(request,
                                            599,
                                            error=exc,
                                            request_time=time.time() -
                                            request.start_time)
                else:
                    response = future.result()
                self.io_loop.add_callback(callback, response)

            future.add_done_callback(handle_future)

        def handle_response(response):
            if raise_error and response.error:
                future.set_exception(response.error)
            else:
                future.set_result(response)

        self.fetch_impl(request, handle_response)
        return future
예제 #10
0
파일: rpc.py 프로젝트: ethaniz/torpc
    def call(self, method_name, *arg, **kwargs):
        _callback = kwargs.get('callback')
        msg_id = next(self._generator)
        request = packer.dumps((method_name, arg))
        buff = struct.pack('!ibi', len(request), RPC_REQUEST, msg_id) + request

        future = TracebackFuture()
        self.add_request_table(msg_id, future)

        if _callback:
            future.add_done_callback(_callback)
        self.write(buff)
        return future
예제 #11
0
    def fetch(self, request, callback=None, **kwargs):
        """Executes a request, asynchronously returning an `HTTPResponse`.

        The request may be either a string URL or an `HTTPRequest` object.
        If it is a string, we construct an `HTTPRequest` using any additional
        kwargs: ``HTTPRequest(request, **kwargs)``

        This method returns a `.Future` whose result is an
        `HTTPResponse`.  The ``Future`` wil raise an `HTTPError` if
        the request returned a non-200 response code.

        If a ``callback`` is given, it will be invoked with the `HTTPResponse`.
        In the callback interface, `HTTPError` is not automatically raised.
        Instead, you must check the response's ``error`` attribute or
        call its `~HTTPResponse.rethrow` method.
        """
        if not isinstance(request, HTTPRequest):
            request = HTTPRequest(url=request, **kwargs)
        # We may modify this (to add Host, Accept-Encoding, etc),
        # so make sure we don't modify the caller's object.  This is also
        # where normal dicts get converted to HTTPHeaders objects.
        request.headers = httputil.HTTPHeaders(request.headers)
        if options.client_trace:
            request.trace.record(Annotation.client_send())
        request = _RequestProxy(request, self.defaults)
        future = TracebackFuture()
        if callback is not None:
            callback = stack_context.wrap(callback)

            def handle_future(future):
                exc = future.exception()
                if isinstance(exc, HTTPError) and exc.response is not None:
                    response = exc.response
                elif exc is not None:
                    response = HTTPResponse(
                        request, 599, error=exc,
                        request_time=time.time() - request.start_time)
                else:
                    response = future.result()
                self.io_loop.add_callback(callback, response)
            future.add_done_callback(handle_future)

        def handle_response(response):
            if response.error:
                future.set_exception(response.error)
            else:
                future.set_result(response)
            if options.client_trace:
                request.trace.record(Annotation.client_recv())
        self.fetch_impl(request, handle_response)
        return future
예제 #12
0
    def mock_fetch(self, request, callback=None, **kwargs):
        future = TracebackFuture()
        if callback is not None:
            callback = stack_context.wrap(callback)

            def handle_future(future):
                response = future.result()
                self.io_loop.add_callback(callback, response)
            future.add_done_callback(handle_future)

        res = MagicMock()
        future.set_result(res)

        return future
예제 #13
0
 def wrapper(*args, **kwargs):
     future = TracebackFuture()
     callback, args, kwargs = replacer.replace(future, args, kwargs)
     if callback is not None:
         future.add_done_callback(
             functools.partial(_auth_future_to_callback, callback))
     def handle_exception(typ, value, tb):
         if future.done():
             return False
         else:
             future.set_exc_info((typ, value, tb))
             return True
     with ExceptionStackContext(handle_exception):
         f(*args, **kwargs)
     return future
예제 #14
0
 def wrapper(*args, **kwargs):
     if replacer.get_old_value(args, kwargs) is not None:
         # If a callaback is present, just call in to the decorated
         # function.  This is a slight optimization (by not creating a
         # Future that is unlikely to be used), but mainly avoids the
         # complexity of running the callback in the expected way.
         return f(*args, **kwargs)
     future = TracebackFuture()
     callback, args, kwargs = replacer.replace(
         lambda value=None: future.set_result(value), args, kwargs)
     f(*args, **kwargs)
     stream = args[0]
     stream._pending_futures.add(future)
     future.add_done_callback(
         lambda fut: stream._pending_futures.discard(fut))
     return future
예제 #15
0
 def wrapper(*args, **kwargs):
     if replacer.get_old_value(args, kwargs) is not None:
         # If a callaback is present, just call in to the decorated
         # function.  This is a slight optimization (by not creating a
         # Future that is unlikely to be used), but mainly avoids the
         # complexity of running the callback in the expected way.
         return f(*args, **kwargs)
     future = TracebackFuture()
     callback, args, kwargs = replacer.replace(
         lambda value=None: future.set_result(value),
         args, kwargs)
     f(*args, **kwargs)
     stream = args[0]
     stream._pending_futures.add(future)
     future.add_done_callback(
         lambda fut: stream._pending_futures.discard(fut))
     return future
예제 #16
0
def fetch_msg(uid, msg_type, data, qos, timeout, callback=None):
    future = TracebackFuture()
    if callback is not None:
        callback = stack_context.wrap(callback)

        def handle_future(future):
            response = future.result()
            IOLoop.current().add_callback(callback, response)
        future.add_done_callback(handle_future)

    def web_handle_response(response=''):
        future.set_result(response)

    WebSocketHandler.send_message(
        uid, msg_type, data,
        qos, timeout, web_handle_response)

    return future
예제 #17
0
    def fetch(self, url, headers=None, body=None, method="GET", callback=None, raise_error=True, **kwargs):
        """very simlar with AsyncHTTPClient.fetch
        """
        if self._closed:
            raise RuntimeError("fetch() called on closed AsyncHTTPClient")
        if isinstance(body, dict):
            body = self.dict2form(body)
            print (body)
        request = HTTPRequest(url=url,method=method,headers=headers,body=body, allow_nonstandard_methods=True, **kwargs)
        # We may modify this (to add Host, Accept-Encoding, etc),
        # so make sure we don't modify the caller's object.  This is also
        # where normal dicts get converted to HTTPHeaders objects.
        request.headers = httputil.HTTPHeaders(request.headers)
        request = _RequestProxy(request, self.defaults)
        future = TracebackFuture()
        if callback is not None:
            callback = stack_context.wrap(callback)

            def handle_future(future):
                exc = future.exception()
                if isinstance(exc, HTTPError) and exc.response is not None:
                    response = exc.response
                elif exc is not None:
                    response = HTTPResponse(
                        request, 599, error=exc,
                        request_time=time.time() - request.start_time)
                else:
                    response = future.result()
                self.io_loop.add_callback(callback, response)
            future.add_done_callback(handle_future)

        def handle_response(response):
            if raise_error and response.error:
                future.set_exception(response.error)
            else:
                try:
                    resp = json.loads(str(response.body))
                    future.set_result(resp)
                except Exception,e:
                    print (e)
                    future.set_result({})
예제 #18
0
파일: gen.py 프로젝트: DriverX/tornado
class WaitIterator(object):
    """Provides an iterator to yield the results of futures as they finish.

    Yielding a set of futures like this:

    ``results = yield [future1, future2]``

    pauses the coroutine until both ``future1`` and ``future2``
    return, and then restarts the coroutine with the results of both
    futures. If either future is an exception, the expression will
    raise that exception and all the results will be lost.

    If you need to get the result of each future as soon as possible,
    or if you need the result of some futures even if others produce
    errors, you can use ``WaitIterator``::

      wait_iterator = gen.WaitIterator(future1, future2)
      while not wait_iterator.done():
          try:
              result = yield wait_iterator.next()
          except Exception as e:
              print("Error {} from {}".format(e, wait_iterator.current_future))
          else:
              print("Result {} received from {} at {}".format(
                  result, wait_iterator.current_future,
                  wait_iterator.current_index))

    Because results are returned as soon as they are available the
    output from the iterator *will not be in the same order as the
    input arguments*. If you need to know which future produced the
    current result, you can use the attributes
    ``WaitIterator.current_future``, or ``WaitIterator.current_index``
    to get the index of the future from the input list. (if keyword
    arguments were used in the construction of the `WaitIterator`,
    ``current_index`` will use the corresponding keyword).

    .. versionadded:: 4.1
    """
    def __init__(self, *args, **kwargs):
        if args and kwargs:
            raise ValueError(
                "You must provide args or kwargs, not both")

        if kwargs:
            self._unfinished = dict((f, k) for (k, f) in kwargs.items())
            futures = list(kwargs.values())
        else:
            self._unfinished = dict((f, i) for (i, f) in enumerate(args))
            futures = args

        self._finished = collections.deque()
        self.current_index = self.current_future = None
        self._running_future = None

        # Use a weak reference to self to avoid cycles that may delay
        # garbage collection.
        self_ref = weakref.ref(self)
        for future in futures:
            future.add_done_callback(functools.partial(
                self._done_callback, self_ref))

    def done(self):
        """Returns True if this iterator has no more results."""
        if self._finished or self._unfinished:
            return False
        # Clear the 'current' values when iteration is done.
        self.current_index = self.current_future = None
        return True

    def next(self):
        """Returns a `.Future` that will yield the next available result.

        Note that this `.Future` will not be the same object as any of
        the inputs.
        """
        self._running_future = TracebackFuture()
        # As long as there is an active _running_future, we must
        # ensure that the WaitIterator is not GC'd (due to the
        # use of weak references in __init__). Add a callback that
        # references self so there is a hard reference that will be
        # cleared automatically when this Future finishes.
        self._running_future.add_done_callback(lambda f: self)

        if self._finished:
            self._return_result(self._finished.popleft())

        return self._running_future

    @staticmethod
    def _done_callback(self_ref, done):
        self = self_ref()
        if self is not None:
            if self._running_future and not self._running_future.done():
                self._return_result(done)
            else:
                self._finished.append(done)

    def _return_result(self, done):
        """Called set the returned future's state that of the future
        we yielded, and set the current future for the iterator.
        """
        chain_future(done, self._running_future)

        self.current_future = done
        self.current_index = self._unfinished.pop(done)
예제 #19
0
    def send_packet(self,
                    channel,
                    message_id_channel,
                    msgtype,
                    data,
                    qos=0,
                    cnt=0):
        """此方法需要返回Future
        """
        packet = Packet(command=Packet.PACKET_SEND,
                        msgtype=msgtype,
                        data=data,
                        qos=qos)

        # 因为一个 wshandler 可能存在多个 channel 中, 所以要各个 wshandler 维护 msg_id
        # 还要 和 这次发送的 message_id_channel 保持好映射
        # 建立映射的同时也要做好取消映射,节约内存

        if packet.qos == 0:
            try:
                self.write_message(packet.raw, binary=True)
            except WebSocketClosedError:
                log.warning(u'发消息前, 客户端关闭了WebSocketClosedError')
        else:
            message_id = self.gen_wshdl_next_message_id()
            self.packet_msg_id_to_channel[message_id] = message_id_channel
            packet.message_id = message_id
            future = TracebackFuture()
            log.debug('channel = %s, message_id_channel = %s, '
                      'packet.message_id = %s' %
                      (channel, message_id_channel, message_id))

            def handle_future(future):
                log.debug('send_packet handle_future func')
                packet = None
                exception = ''
                try:
                    packet = future.result()
                except:
                    # 有可能是没发确认就 on_close 了
                    exception = future.exception()
                    # 1.如果timeout了,是不会调用下面的 handle_response
                    #   然后也不会再调用 handle_future, 不会有 add_callback
                    # 2.客户端不发 ack 而直接 close
                    # 会调用 handle_response(exception='on_close')
                IOLoop.current().add_callback(self.send_packet_cb, channel,
                                              message_id, packet, exception)

            future.add_done_callback(handle_future)

            def handle_response(packet=None, exception=None):
                if packet:
                    future.set_result(packet)
                else:
                    future.set_exception(exception)

            self.future_rsp_hl[message_id] = handle_response

            toh = IOLoop.current().add_timeout(time.time() + self.RB_Timeout,
                                               self.send_packet_cb_timeout,
                                               channel, message_id, packet,
                                               cnt)

            self.rsp_timeout_hl[message_id] = toh
            try:
                self.write_message(packet.raw, binary=True)
                log.debug('self.write_message = %s' % packet.raw)
            except Exception, e:
                log.warning(e)
                log.warning(traceback.format_exc())

            return future
예제 #20
0
파일: tornado.py 프로젝트: tristeng/kazoo
class AsyncResult(object):
    """
    Essentially a wrapper for a Tornado TracebackFuture
    """
    def __init__(self, future=None):
        if future is not None:
            self._future = future
        else:
            self._future = TracebackFuture()
            self._future.add_done_callback(functools.partial(async_result_complete, self))
        self._condition = threading.Condition()

    def ready(self):
        """Return `True` if and only if it holds a value or an
        exception"""
        return self._future.done()

    def successful(self):
        """Return `True` if and only if it is ready and holds a
        value"""
        return self._future.exception() is None

    @property
    def exception(self):
        return self._future.exception()

    def set(self, value=None):
        """Store the value. Wake up the waiters.

        :param value: Value to store as the result.

        Any waiters blocking on :meth:`get` or :meth:`wait` are woken
        up. Sequential calls to :meth:`wait` and :meth:`get` will not
        block at all."""
        with self._condition:
            self._future.set_result(value)

    def set_exception(self, exception):
        """Store the exception. Wake up the waiters.

        :param exception: Exception to raise when fetching the value.

        Any waiters blocking on :meth:`get` or :meth:`wait` are woken
        up. Sequential calls to :meth:`wait` and :meth:`get` will not
        block at all."""
        with self._condition:
            self._future.set_exception(exception)

    def get(self, block=True, timeout=None):
        """Return the stored value or raise the exception

        :param block: Whether this method should block or return
                      immediately.
        :type block: bool
        :param timeout: How long to wait for a value when `block` is
                        `True`.
        :type timeout: float

        If this instance already holds a value / an exception, return /
        raise it immediately. Otherwise, block until :meth:`set` or
        :meth:`set_exception` has been called or until the optional
        timeout occurs."""
        with self._condition:
            if self.ready():
                return self._future.result()
            elif block:
                self._condition.wait(timeout)
                return self._future.result()

            # if we get to this point we timeout
            raise KazooTimeoutError()

    def get_nowait(self):
        """Return the value or raise the exception without blocking.

        If nothing is available, raise the Timeout exception class on
        the associated :class:`IHandler` interface."""
        return self._future.result()

    def wait(self, timeout=None):
        """Block until the instance is ready.

        :param timeout: How long to wait for a value
        :type timeout: float

        If this instance already holds a value / an exception, return /
        raise it immediately. Otherwise, block until :meth:`set` or
        :meth:`set_exception` has been called or until the optional
        timeout occurs."""
        with self._condition:
            self._condition.wait(timeout)
        return self.ready()

    def rawlink(self, callback):
        """Register a callback to call when a value or an exception is
        set

        :param callback:
            A callback function to call after :meth:`set` or
            :meth:`set_exception` has been called. This function will
            be passed a single argument, this instance.
        :type callback: func

        """
        def on_callback(future):
            callback(AsyncResult(future))

        IOLoop.current().add_future(self._future, on_callback)

    def unlink(self, callback):
        """Remove the callback set by :meth:`rawlink`

        :param callback: A callback function to remove.
        :type callback: func

        """

    def notify(self):
        self._condition.notify_all()
예제 #21
0
class WaitIterator(object):
    """Provides an iterator to yield the results of futures as they finish.

    Yielding a set of futures like this:

    ``results = yield [future1, future2]``

    pauses the coroutine until both ``future1`` and ``future2``
    return, and then restarts the coroutine with the results of both
    futures. If either future is an exception, the expression will
    raise that exception and all the results will be lost.

    If you need to get the result of each future as soon as possible,
    or if you need the result of some futures even if others produce
    errors, you can use ``WaitIterator``::

      wait_iterator = gen.WaitIterator(future1, future2)
      while not wait_iterator.done():
          try:
              result = yield wait_iterator.next()
          except Exception as e:
              print("Error {} from {}".format(e, wait_iterator.current_future))
          else:
              print("Result {} recieved from {} at {}".format(
                  result, wait_iterator.current_future,
                  wait_iterator.current_index))

    Because results are returned as soon as they are available the
    output from the iterator *will not be in the same order as the
    input arguments*. If you need to know which future produced the
    current result, you can use the attributes
    ``WaitIterator.current_future``, or ``WaitIterator.current_index``
    to get the index of the future from the input list. (if keyword
    arguments were used in the construction of the `WaitIterator`,
    ``current_index`` will use the corresponding keyword).

    .. versionadded:: 4.1
    """
    def __init__(self, *args, **kwargs):
        if args and kwargs:
            raise ValueError(
                "You must provide args or kwargs, not both")

        if kwargs:
            self._unfinished = dict((f, k) for (k, f) in kwargs.items())
            futures = list(kwargs.values())
        else:
            self._unfinished = dict((f, i) for (i, f) in enumerate(args))
            futures = args

        self._finished = collections.deque()
        self.current_index = self.current_future = None
        self._running_future = None

        # Use a weak reference to self to avoid cycles that may delay
        # garbage collection.
        self_ref = weakref.ref(self)
        for future in futures:
            future.add_done_callback(functools.partial(
                self._done_callback, self_ref))

    def done(self):
        """Returns True if this iterator has no more results."""
        if self._finished or self._unfinished:
            return False
        # Clear the 'current' values when iteration is done.
        self.current_index = self.current_future = None
        return True

    def next(self):
        """Returns a `.Future` that will yield the next available result.

        Note that this `.Future` will not be the same object as any of
        the inputs.
        """
        self._running_future = TracebackFuture()
        # As long as there is an active _running_future, we must
        # ensure that the WaitIterator is not GC'd (due to the
        # use of weak references in __init__). Add a callback that
        # references self so there is a hard reference that will be
        # cleared automatically when this Future finishes.
        self._running_future.add_done_callback(lambda f: self)

        if self._finished:
            self._return_result(self._finished.popleft())

        return self._running_future

    @staticmethod
    def _done_callback(self_ref, done):
        self = self_ref()
        if self is not None:
            if self._running_future and not self._running_future.done():
                self._return_result(done)
            else:
                self._finished.append(done)

    def _return_result(self, done):
        """Called set the returned future's state that of the future
        we yielded, and set the current future for the iterator.
        """
        chain_future(done, self._running_future)

        self.current_future = done
        self.current_index = self._unfinished.pop(done)