def _execute(self, transforms, *args, **kwargs): """Executes this request with the given output transforms. This is basically a copy of tornado's `_execute()` method. The only difference is the expected result. Tornado expects the result to be `None`, where we want this to be a :py:class:Model.""" verb = self.request.method.lower() headers = self.request.headers self._transforms = transforms try: if self.request.method not in self.SUPPORTED_METHODS: raise HTTPError(405) self.path_args = [self.decode_argument(arg) for arg in args] self.path_kwargs = dict((k, self.decode_argument(v, name=k)) for (k, v) in kwargs.items()) # If XSRF cookies are turned on, reject form submissions without # the proper cookie if self.request.method not in ("GET", "HEAD", "OPTIONS") and \ self.application.settings.get("xsrf_cookies"): self.check_xsrf_cookie() result = self.prepare() if is_future(result): result = yield result if result is not None: raise TypeError("Expected None, got %r" % result) if self._prepared_future is not None: # Tell the Application we've finished with prepare() # and are ready for the body to arrive. self._prepared_future.set_result(None) if self._finished: return if _has_stream_request_body(self.__class__): # In streaming mode request.body is a Future that signals # the body has been completely received. The Future has no # result; the data has been passed to self.data_received # instead. try: yield self.request.body except iostream.StreamClosedError: return method = getattr(self, self.request.method.lower()) result = method(*self.path_args, **self.path_kwargs) if is_future(result): result = yield result if result is not None: self._provide_result(verb, headers, result) if self._auto_finish and not self._finished: self.finish() except Exception as e: self._handle_request_exception(e) if (self._prepared_future is not None and not self._prepared_future.done()): # In case we failed before setting _prepared_future, do it # now (to unblock the HTTP server). Note that this is not # in a finally block to avoid GC issues prior to Python 3.4. self._prepared_future.set_result(None)
def handle_yield(self, yielded): if isinstance(yielded, list): if all(is_future(f) for f in yielded): yielded = multi_future(yielded) else: yielded = Multi(yielded) elif isinstance(yielded, dict): if all(is_future(f) for f in yielded.values()): yielded = multi_future(yielded) else: yielded = Multi(yielded) if isinstance(yielded, YieldPoint): self.future = TracebackFuture() def start_yield_point(): try: yielded.start(self) if yielded.is_ready(): self.future.set_result( yielded.get_result()) else: self.yield_point = yielded except Exception: self.future = TracebackFuture() self.future.set_exc_info(sys.exc_info()) if self.stack_context_deactivate is None: # Start a stack context if this is the first # YieldPoint we've seen. with stack_context.ExceptionStackContext( self.handle_exception) as deactivate: self.stack_context_deactivate = deactivate def cb(): start_yield_point() self.run() self.io_loop.add_callback(cb) return False else: start_yield_point() elif is_future(yielded): self.future = yielded if not self.future.done() or self.future is moment: self.io_loop.add_future( self.future, lambda f: self.run()) return False else: self.future = TracebackFuture() self.future.set_exception(BadYieldError( "yielded unknown object %r" % (yielded,))) return True
def on_channel_closed(self, channel, reply_code, reply_text): """Invoked by pika when RabbitMQ unexpectedly closes the channel. Channels are usually closed if you attempt to do something that violates the protocol, such as re-declare an exchange or queue with different parameters. In this case, we'll close the connection to shutdown the object. :param pika.channel.Channel channel: The AMQP Channel :param int reply_code: The AMQP reply code :param str reply_text: The AMQP reply text """ LOGGER.warning('Channel %i closed: (%s) %s', channel.channel_number, reply_code, reply_text) self.statsd_incr('amqp.channel_closed') if concurrent.is_future(self.event_processed): self.set_state(self.STATE_RECONNECTING) def on_open(new_channel): self.on_channel_open(new_channel) self.set_state(self.STATE_PROCESSING) exc = EventError(self.current_event, reply_text) self.event_processed.set_exception(exc) return self.connection.channel(on_open) del self.channel self.on_ready_to_stop()
def maybe_future(x): if is_future(x): return x else: fut = Future() fut.set_result(x) return fut
def add_future( self, future: "Union[Future[_T], concurrent.futures.Future[_T]]", callback: Callable[["Future[_T]"], None], ) -> None: """Schedules a callback on the ``IOLoop`` when the given `.Future` is finished. The callback is invoked with one argument, the `.Future`. This method only accepts `.Future` objects and not other awaitables (unlike most of Tornado where the two are interchangeable). """ if isinstance(future, Future): # Note that we specifically do not want the inline behavior of # tornado.concurrent.future_add_done_callback. We always want # this callback scheduled on the next IOLoop iteration (which # asyncio.Future always does). # # Wrap the callback in self._run_callback so we control # the error logging (i.e. it goes to tornado.log.app_log # instead of asyncio's log). future.add_done_callback( lambda f: self._run_callback(functools.partial(callback, future)) ) else: assert is_future(future) # For concurrent futures, we use self.add_callback, so # it's fine if future_add_done_callback inlines that call. future_add_done_callback( future, lambda f: self.add_callback(callback, future) )
def on_message(self, message): try: message = json.loads(message) dev = message["dev"] circuit = message["circuit"] try: value = message["value"] except: value = None try: cmd = message["cmd"] except: cmd = "set" try: device = Devices.by_name(dev, circuit) # result = device.set(value) func = getattr(device, cmd) if value is not None: result = func(value) else: result = func() if is_future(result): result = yield result print result except Exception, E: print E except: print "Skipping WS message: " + message # skip it since we do not understand this message.... pass
def refresh(self): """Load dynamic credentials from the AWS Instance Metadata and user data HTTP API. :raises: tornado_aws.exceptions.NoCredentialsError """ LOGGER.debug('Refreshing EC2 IAM Credentials') async = isinstance(self._client, httpclient.AsyncHTTPClient) future = concurrent.TracebackFuture() if async else None try: result = self._fetch_credentials(async) if concurrent.is_future(result): def on_complete(response): exception = response.exception() if exception: if isinstance(exception, httpclient.HTTPError) and \ exception.code == 599: future.set_exception( exceptions.NoCredentialsError()) else: future.set_exception(exception) return self._assign_credentials(response.result()) future.set_result(True) self._ioloop.add_future(result, on_complete) else: self._assign_credentials(result) except (httpclient.HTTPError, OSError) as error: LOGGER.error('Error Fetching Credentials: %s', error) raise exceptions.NoCredentialsError() return future
def new_fn(self, *args, **kwargs): result = fn(self, *args, **kwargs) if not is_future(result): # If the function doesn't return a future, its exeption or result # is available to the caller right away. No need to switch control # with greenlets. return result current = greenlet.getcurrent() assert current.parent is not None, "TornadoAction can only be used from inside a child greenlet." def callback(future): if future.exception(): self.io_loop.add_callback(current.throw, *future.exc_info()) else: self.io_loop.add_callback(current.switch, future.result()) # Otherwise, switch to parent and schedule to switch back when the # result is available. # A note about add_done_callback: It executes the callback right away # if the future has already finished executing. That's a problem # because we don't want the greenlet switch back to current to happen # until we've switched to parent first. So, io_loop.add_callback is # used to schedule the future callback. This ensures that we switch to # parent first. self.io_loop.add_callback(result.add_done_callback, callback) return current.parent.switch()
def convert_yielded(yielded): """Convert a yielded object into a `.Future`. The default implementation accepts lists, dictionaries, and Futures. If the `~functools.singledispatch` library is available, this function may be extended to support additional types. For example:: @convert_yielded.register(asyncio.Future) def _(asyncio_future): return tornado.platform.asyncio.to_tornado_future(asyncio_future) .. versionadded:: 4.1 """ # Lists and dicts containing YieldPoints were handled earlier. if yielded is None: return moment elif isinstance(yielded, (list, dict)): return multi(yielded) elif is_future(yielded): return yielded elif isawaitable(yielded): return _wrap_awaitable(yielded) else: raise BadYieldError("yielded unknown object %r" % (yielded,))
def stop(self, io_loop): """ Asynchronously stop the application. :param tornado.ioloop.IOLoop io_loop: loop to run until all callbacks, timeouts, and queued calls are complete Call this method to start the application shutdown process. The IOLoop will be stopped once the application is completely shut down. """ running_async = False shutdown = _ShutdownHandler(io_loop) for callback in self.on_shutdown_callbacks: try: maybe_future = callback(self.tornado_application) if asyncio.iscoroutine(maybe_future): maybe_future = asyncio.create_task(maybe_future) if concurrent.is_future(maybe_future): shutdown.add_future(maybe_future) running_async = True except Exception as error: self.logger.warning('exception raised from shutdown ' 'callback %r, ignored: %s', callback, error, exc_info=1) if not running_async: shutdown.on_shutdown_ready()
def handle_request(self, topic, message): if topic == self.subtopic: # event from proxy received try: data = etree.fromstring(message, PluginRegistry.getEventParser()) event_type = stripNs(data.xpath('/g:Event/*', namespaces={'g': "http://www.gonicus.de/Events"})[0].tag) if event_type == "ClientLeave": proxy_id = str(data.ClientLeave.Id) registry = PluginRegistry.getInstance("BackendRegistry") registry.unregisterBackend(proxy_id) except etree.XMLSyntaxError as e: self.log.error("Event parsing error: %s" % e) elif topic.startswith(self.subtopic): response_topic = "%s/response" % "/".join(topic.split("/")[0:4]) try: id_, res = self.process(topic, message) if is_future(res): res = yield res response = dumps({"result": res, "id": id_}) self.log.debug("MQTT-RPC response: %s on topic %s" % (response, topic)) except Exception as e: err = str(e) self.log.error("MQTT RPC call error: %s" % err) response = dumps({'id': topic.split("/")[-2], 'error': err}) # Get rid of it... self.mqtt.send_message(response, topic=response_topic, qos=2) else: self.log.warning("unhandled topic request received: %s" % topic)
def handle(self, endpoint, *args, **kwargs): """ almost identical to Resource.handle, except the way we handle the return value of view_method. """ method = self.request_method() try: if not method in self.http_methods.get(endpoint, {}): raise MethodNotImplemented( "Unsupported method '{0}' for {1} endpoint.".format( method, endpoint ) ) if not self.is_authenticated(): raise Unauthorized() self.data = self.deserialize(method, endpoint, self.request_body()) view_method = getattr(self, self.http_methods[endpoint][method]) data = view_method(*args, **kwargs) if is_future(data): # need to check if the view_method is a generator or not data = yield data serialized = self.serialize(method, endpoint, data) except Exception as err: raise gen.Return(self.handle_error(err)) status = self.status_map.get(self.http_methods[endpoint][method], OK) raise gen.Return(self.build_response(serialized, status=status))
def convert_yielded(yielded: _Yieldable) -> Future: """Convert a yielded object into a `.Future`. The default implementation accepts lists, dictionaries, and Futures. If the `~functools.singledispatch` library is available, this function may be extended to support additional types. For example:: @convert_yielded.register(asyncio.Future) def _(asyncio_future): return tornado.platform.asyncio.to_tornado_future(asyncio_future) .. versionadded:: 4.1 """ if yielded is None or yielded is moment: return moment elif yielded is _null_future: return _null_future elif isinstance(yielded, (list, dict)): return multi(yielded) # type: ignore elif is_future(yielded): return typing.cast(Future, yielded) elif isawaitable(yielded): return _wrap_awaitable(yielded) # type: ignore else: raise BadYieldError("yielded unknown object %r" % (yielded,))
def on_message(self, message): ''' handle an rpc calls ''' data = json_decode(message) for id_, action, kwargs in data.get("requests"): context = self.micro_context( self._client_id, id_, action, self._cookies_, self) try: LOGGER.info( "%s %s %s %r", id(self), context.action_id, context.action, kwargs) service = self.settings["services"].get(context.action) if service is None: raise Exception("No such service {}".format(context.action)) result = service.perform(context, ** kwargs) if concurrent.is_future(result): result.add_done_callback( functools.partial(self.handle_future, service, context, False)) else: self.handle_result(service, context, result) except Exception as ex: self.write_err(context, ex)
def _run_callback(self, callback): try: ret = callback() if ret is not None and is_future(ret): self.add_future(ret, lambda f: f.result()) except Exception: self.handle_callback_exception(callback)
def onRecvStream(self, stream, msg): # If the handler triggers an exception, pyzmq will disable it # Here we catch any exception and just log it, so that processing # can continue try: cname = stream.channel_name self.counters[cname] += 1 #buf_len = self.counters[cname] - self.counters[output_cname] #self.logger.debug('Received on %s: %d', cname, buf_len) handler = self.get_recv_handler(cname) fut = handler(msg) if is_future(fut): self.loop.add_future(fut, self.onFuture) output_cname = self.channels[cname].drained_by if output_cname: buf_len = self.streams[output_cname]._send_queue.qsize() hwm = self.channels[cname].hwm if buf_len >= (hwm - (hwm * 0.2)): msg = "Pausing receive on: %s (Buffered: %d, HWM: %d)" hwm = self.channels[cname].hwm self.logger.info(msg, cname, buf_len, hwm) stream.stop_on_recv() except Error as err: self.logger.exception(err) self.init_db() except Exception as err: self.logger.exception(err)
def _wrapper(self, *args, **kwargs): try: # 因为这段代码是在 @gen.coroutine 装饰器中, # 如果这段代码发生异常,没有用 except 捕获的话就无法自动调用 write_error validate_success = True errors = None if input_schema is not None: v = cerberus.Validator(input_schema) # 允许提交未知的数据 v.allow_unknown = True if not v.validate(self.post_data): validate_success = False errors = v.errors if not validate_success: logger.warning(errors) # 验证失败,返回错误 self.fail(msg='提交的数据格式不正确') else: # Call the request_handler method ret = func(self, *args, **kwargs) if is_future(ret): yield ret # 如果 rh_method 用了 coroutine,并且这个函数中抛出了异常, # 但是这里没有用 yield 的话,就无法捕获到异常,从而调用 write_error logger.debug('yield') except gen.Return: pass except Exception as e: logger.debug(traceback.format_exc()) logger.debug(e) self.write_error(GATEWAY_ERROR_STATUS_CODE, exc_info=sys.exc_info())
def execute_next(self, request, types, process_object, *args, **kwargs): midd = None if types == _TCALL: midd = ('call_midds', 'process_call',) elif types == _TREQ: midd = ('request_midds', 'process_request',) elif types == _TREN: midd = ('render_midds', 'process_render',) elif types == _TRES: midd = ('response_midds', 'process_response',) elif types == _TEND: midd = ('end_midds', 'process_endcall',) elif types == _TEXC: midd = ('exc_midds', 'process_exception',) if midd: while 1: method = self._get_func(request, midd[0], midd[1]) if method and callable(method): clear = partial(self.clear_all, request) result = method(process_object, clear, *args, **kwargs) if is_future(result): result = yield result if result: break else: break
def _do_all_execute_forasync(self, handler, clear, method_name, **kwargs): for c_module in self.common_modules: result = self._execute_module(handler, clear, c_module, getattr(c_module, method_name), **kwargs) if is_future(result): result = yield result if result: raise gen.Return(1) for name, r_module in self.route_modules.items(): for md in r_module: result = self._execute_module(handler, clear, md, getattr(md, method_name), name, **kwargs) if is_future(result): result = yield result if result: raise gen.Return(1)
def convert_yielded(yielded): if isinstance(yielded, (list, dict)): return multi_future(yielded) elif is_future(yielded): return yielded else: raise BadYieldError("yielded unknown object %r" % (yielded,))
def prepare(self): maybe_future = super(SimpleHandler, self).prepare() if concurrent.is_future(maybe_future): yield maybe_future if 'Correlation-ID' in self.request.headers: self.set_metric_tag('correlation_id', self.request.headers['Correlation-ID'])
def capture(self, fn_ret): """ """ result = fn_ret if is_future(result): # import is_future result = yield result return result
def _wrapper(self, *args, **kwargs): # In case the specified input_schema is ``None``, we # don't json.loads the input, but just set it to ``None`` # instead. if input_schema is not None: # Attempt to json.loads the input try: # TODO: Assuming UTF-8 encoding for all requests, # find a nice way of determining this from charset # in headers if provided encoding = "UTF-8" input_ = json.loads(self.request.body.decode(encoding)) except ValueError as e: raise jsonschema.ValidationError( "Input is malformed; could not decode JSON object." ) # Validate the received input jsonschema.validate( input_, input_schema ) else: input_ = None # A json.loads'd version of self.request["body"] is now available # as self.body setattr(self, "body", input_) # Call the requesthandler method output = rh_method(self, *args, **kwargs) # If the rh_method returned a Future a la `raise Return(value)` # we grab the output. if is_future(output): output = yield output if output_schema is not None: # We wrap output in an object before validating in case # output is a string (and ergo not a validatable JSON object) try: jsonschema.validate( {"result": output}, { "type": "object", "properties": { "result": output_schema }, "required": ["result"] } ) except jsonschema.ValidationError as e: # We essentially re-raise this as a TypeError because # we don't want this error data passed back to the client # because it's a fault on our end. The client should # only see a 500 - Internal Server Error. raise TypeError(str(e)) # If no ValidationError has been raised up until here, we write # back output self.success(output)
def run(child_gr, *args, **kwargs): try: result = func(*args, **kwargs) if not is_future(result): return child_gr.switch(result) except Exception as e: result = Future() result.set_exception(e) return ioloop.add_future(result, child_gr.switch)
def multi_future(children, quiet_exceptions=()): """Wait for multiple asynchronous futures in parallel. This function is similar to `multi`, but does not support `YieldPoints <YieldPoint>`. .. versionadded:: 4.0 .. versionchanged:: 4.2 If multiple ``Futures`` fail, any exceptions after the first (which is raised) will be logged. Added the ``quiet_exceptions`` argument to suppress this logging for selected exception types. .. deprecated:: 4.3 Use `multi` instead. """ if isinstance(children, dict): keys = list(children.keys()) children = children.values() else: keys = None children = list(map(convert_yielded, children)) assert all(is_future(i) for i in children) unfinished_children = set(children) future = _create_future() if not children: future_set_result_unless_cancelled(future, {} if keys is not None else []) def callback(f): unfinished_children.remove(f) if not unfinished_children: result_list = [] for f in children: try: result_list.append(f.result()) except Exception as e: if future.done(): if not isinstance(e, quiet_exceptions): app_log.error("Multiple exceptions in yield list", exc_info=True) else: future_set_exc_info(future, sys.exc_info()) if not future.done(): if keys is not None: future_set_result_unless_cancelled(future, dict(zip(keys, result_list))) else: future_set_result_unless_cancelled(future, result_list) listening = set() for f in children: if f not in listening: listening.add(f) future_add_done_callback(f, callback) return future
def add_future(self, future, callback): """Schedules a callback on the ``IOLoop`` when the given `.Future` is finished. The callback is invoked with one argument, the `.Future`. """ assert is_future(future) callback = stack_context.wrap(callback) future.add_done_callback(lambda future: self.add_callback(callback, future))
def _execute(self): """Invoke the lifecycle methods for a message (prepare, process, on_finish), yielding if any are coroutines. """ for call in (self.prepare, self.process, self.on_finish): self.logger.debug('Invoking %r', call) result = call() if concurrent.is_future(result): yield result
def execute_next_for_async(self, request, call_list, process_object, *args, **kwargs): while call_list and len(call_list): try: result = self._execute(request, call_list, process_object, *args, **kwargs) if is_future(result): result = yield result if result: break except NotCallableError: break
def do_call_request_method(self): """ """ method = getattr(self, self.request.method.lower()) result = method(*self.path_args, **self.path_kwargs) if is_future(result): result = yield result if result is not None: raise TypeError("Expected None, got %r" % result) if self._auto_finish and not self._finished: self.finish()
def __init__(self, children): self.keys = None if isinstance(children, dict): self.keys = list(children.keys()) children = children.values() self.children = [] for i in children: if is_future(i): i = YieldFuture(i) self.children.append(i) assert all(isinstance(i, YieldPoint) for i in self.children) self.unfinished_children = set(self.children)
def _poll(self): """Infinite coroutine for draining the queue. """ while True: try: incoming_msg = self._queue.get_nowait() except QueueEmpty: self.logger.debug('Source queue empty, waiting...') incoming_msg = yield self._queue.get() outgoing_msg_future = self.transducer(incoming_msg) if is_future(outgoing_msg_future): outgoing_msg = yield outgoing_msg_future yield self._maybe_send(outgoing_msg)
def patch(self, id_): ''' PATCH method, see `spec <http://jsonapi.org/format/1.0/#crud-updating>`__. Decorate with :py:func:`tornado.gen.coroutine` when subclassing. ''' if not id_: raise APIError(status.HTTP_400_BAD_REQUEST, 'Missing ID') data = self._get_request_data(_schemas.patchDataSchema()) if data['id'] != id_: raise APIError(status.HTTP_400_BAD_REQUEST, 'ID mismatch') exists = self._resource.exists(id_) while is_future(exists): exists = yield exists if not exists: raise APIError(status.HTTP_404_NOT_FOUND, 'No such resource') res = self._get_resource(data, validate=False) resource = self._resource.update(id_, res) while is_future(resource): resource = yield resource if not resource: raise APIError() self.render(resource)
def maybe_future(x): """Converts ``x`` into a `.Future`. If ``x`` is already a `.Future`, it is simply returned; otherwise it is wrapped in a new `.Future`. This is suitable for use as ``result = yield gen.maybe_future(f())`` when you don't know whether ``f()`` returns a `.Future` or not. """ if is_future(x): return x else: fut = Future() fut.set_result(x) return fut
def add_future(self, future, callback): """Schedules a callback on the ``IOLoop`` when the given `.Future` is finished. The callback is invoked with one argument, the `.Future`. This method only accepts `.Future` objects and not other awaitables (unlike most of Tornado where the two are interchangeable). """ assert is_future(future) future_add_done_callback( future, lambda future: self.add_callback(callback, future))
def method(*args, **kwds): client = yield self.get_client() api = getattr(client, name, None) will_put_back = True try: if api and (callable(api) or is_future(api)): raise gen.Return((yield api(*args, **kwds))) raise AttributeError("%s not found in %s" % (name, client)) except client.TTransportException: will_put_back = False client.close() raise finally: if will_put_back: self.put_back_connection(client)
def wrapper(self, *args, **kwargs): self._auto_finish = False with stack_context.ExceptionStackContext( self._stack_context_handle_exception): result = method(self, *args, **kwargs) if is_future(result): def future_complete(f): f.result() if not self._finished: self.finish() IOLoop.current().add_future(result, future_complete) return None return result
def read(self, id_): with (yield self.cursor(self.connection)) as cursor: cur = dbapiext.execute_f( cursor, "select %s from %s where id = %X", self.columns + ["id"], self._tablename, id_, ) if is_future(cur): cur = yield cur row = cur.fetchone() if not row: return None return DBAPI2Resource.ResourceObject(self, row)
def _run_callback(self, callback): """Runs a callback with error handling. For use in subclasses. """ try: ret = callback() if ret is not None and is_future(ret): # Functions that return Futures typically swallow all # exceptions and store them in the Future. If a Future # makes it out to the IOLoop, ensure its exception (if any) # gets logged too. self.add_future(ret, lambda f: f.result()) except Exception: self.handle_callback_exception(callback)
def __init__(self, children, quiet_exceptions=()): self.keys = None if isinstance(children, dict): self.keys = list(children.keys()) children = children.values() self.children = [] for i in children: if not isinstance(i, YieldPoint): i = convert_yielded(i) if is_future(i): i = YieldFuture(i) self.children.append(i) assert all(isinstance(i, YieldPoint) for i in self.children) self.unfinished_children = set(self.children) self.quiet_exceptions = quiet_exceptions
def _(*args, **kwargs): self._server.handing_count += 1 try: child_gr = greenlet.getcurrent() main = child_gr.parent if main is None: return func(*args, **kwargs) ioloop.add_callback(run, child_gr, *args, **kwargs) result = main.switch() if is_future(result): result = result.result() return result finally: self._server.handing_count -= 1
def on_message(self, message): try: message = json.loads(message) try: cmd = message["cmd"] except: cmd = None #get FULL state of each IO if cmd == "all": result = {} devices = [INPUT, RELAY, AI, AO, SENSOR] for dev in devices: result += map(lambda dev: dev.full(), Devices.by_int(dev)) self.write_message(json.dumps(result)) #set device state elif cmd is not None: dev = message["dev"] circuit = message["circuit"] try: value = message["value"] except: value = None try: device = Devices.by_name(dev, circuit) # result = device.set(value) func = getattr(device, cmd) #print type(value), value if value is not None: if type(value) == dict: result = func(**value) else: result = func(value) else: result = func() if is_future(result): result = yield result #send response only to the client requesting full info if cmd == "full": self.write_message(result) #nebo except Exception as e: except Exception, E: logger.error("Exc: %s", str(E)) #self.write_message({"error_msg":"Couldn't process this request"}) except: logger.debug("Skipping WS message: %s", message) # skip it since we do not understand this message.... pass
def multi_future(children): """Wait for multiple asynchronous futures in parallel. Takes a list of ``Futures`` (but *not* other ``YieldPoints``) and returns a new Future that resolves when all the other Futures are done. If all the ``Futures`` succeeded, the returned Future's result is a list of their results. If any failed, the returned Future raises the exception of the first one to fail. Instead of a list, the argument may also be a dictionary whose values are Futures, in which case a parallel dictionary is returned mapping the same keys to their results. It is not necessary to call `multi_future` explcitly, since the engine will do so automatically when the generator yields a list of `Futures`. This function is faster than the `Multi` `YieldPoint` because it does not require the creation of a stack context. .. versionadded:: 4.0 """ if isinstance(children, dict): keys = list(children.keys()) children = children.values() else: keys = None assert all(is_future(i) for i in children) unfinished_children = set(children) future = Future() if not children: future.set_result({} if keys is not None else []) def callback(f): unfinished_children.remove(f) if not unfinished_children: try: result_list = [i.result() for i in children] except Exception: future.set_exc_info(sys.exc_info()) else: if keys is not None: future.set_result(dict(zip(keys, result_list))) else: future.set_result(result_list) for f in children: f.add_done_callback(callback) return future
def _wrapper(self, *args, **kwargs): validation_ruleset = getattr(self, "validation_ruleset") input_schema = create_object_schema_from_validation_ruleset(validation_ruleset) if input_schema is not None: try: encoding = "UTF-8" input_ = json.loads(self.request.body.decode(encoding)) except ValueError: raise jsonschema.ValidationError( "Input is malformed; could not decode JSON object." ) if use_defaults: input_ = input_schema_clean(input_, input_schema) jsonschema.validate( input_, input_schema, cls=validator_cls, format_checker=format_checker ) else: input_ = None setattr(self, "body", input_) output = rh_method(self, *args, **kwargs) if is_future(output): output = yield output if not output and on_empty_404: raise APIError(404, "Resource not found.") if output_schema is not None: try: jsonschema.validate( {"result": output}, { "type": "object", "properties": { "result": output_schema }, "required": ["result"] } ) except jsonschema.ValidationError as error: raise TypeError(str(error)) self.success(output)
def _write_body(self, start_read): if self.request.body is not None: self.connection.write(self.request.body) elif self.request.body_producer is not None: fut = self.request.body_producer(self.connection.write) if is_future(fut): def on_body_written(fut): fut.result() self.connection.finish() if start_read: self._read_response() self.io_loop.add_future(fut, on_body_written) return self.connection.finish() if start_read: self._read_response()
def run(): try: result = func() if result is not None: from tornado.gen import convert_yielded result = convert_yielded(result) except Exception: future_cell[0] = Future() future_set_exc_info(future_cell[0], sys.exc_info()) else: if is_future(result): future_cell[0] = result else: future_cell[0] = Future() future_cell[0].set_result(result) self.add_future(future_cell[0], lambda future: self.stop())
def _wrapper(self, *args, **kwargs): result = rh_method(self, *args, **kwargs) if is_future(result): result = yield result if result is not None: try: jsonschema.validate(result, schema, format_checker=format_checker) except jsonschema.ValidationError: log.exception("Invalid response") raise APIError(500, "Invalid response") self.write_json(result) self.finish()
def execute_next(self, request, types, process_object, *args, **kwargs): midd = None if types == _TCALL: midd = ( 'call_midds', 'process_call', ) elif types == _TREQ: midd = ( 'request_midds', 'process_request', ) elif types == _TREN: midd = ( 'render_midds', 'process_render', ) elif types == _TRES: midd = ( 'response_midds', 'process_response', ) elif types == _TEND: midd = ( 'end_midds', 'process_endcall', ) elif types == _TEXC: midd = ( 'exc_midds', 'process_exception', ) if midd: while 1: method = self._get_func(request, midd[0], midd[1]) if method and callable(method): clear = partial(self.clear_all, request) result = method(process_object, clear, *args, **kwargs) if is_future(result): result = yield result if result: break else: break
def execute_next_for_async(self, request, types, process_object, *args, **kwargs): midd = self._call_mapper.get(types, None) if midd: while 1: method = self._get_func(request, midd[0], midd[1]) if method and callable(method): clear = partial(self.clear_all, request) result = method(process_object, clear, *args, **kwargs) if is_future(result): result = yield result if result: break else: break
def run(): """execute dest func""" try: result = func(*args, **kwargs) if result is not None: result = convert_yielded(result) except Exception: future_cell[0] = Future() future_set_exc_info(future_cell[0], sys.exc_info()) else: if is_future(result): future_cell[0] = result else: future_cell[0] = Future() future_cell[0].set_result(result) IOLoop.current().add_future(future_cell[0], lambda future: check_stop())
def _create_table(self): types = [ self._types_mapping[self._schema.propinfo(c)["type"]] + (" not null" if c in self._schema.__required__ else "") for c in self.columns ] column_defs = [self._create_primary_key()] + [ "{} {}".format(c, t) for c, t in zip(self.columns, types) ] with (yield self.cursor(self.connection, transaction=True)) as cursor: cur = dbapiext.execute_f( cursor, "create table if not exists %s (%s)", self._tablename, column_defs, ) if is_future(cur): yield cur
def validate_output(output): # in case output is a future, we can be sure it is finished if is_future(output): output = output.result() json_data = validate_json(json_data=output, json_schema=output_schema, json_example=output_example, validator_cls=validator_cls, format_checker=format_checker, on_empty_404=on_empty_404) if json_data and write_json and \ not self._finished: if isinstance(self, JSendMixin): self.success(json_data) else: self.write(json_data)
def apply_future(cls, func, *args, **kwargs): """Execute coroutine in a standalone tornado ioloop. :param func: coroutine function or regular function. :param kwargs: if `callback` in kwargs dict, the value will be treated as a function and called when coroutine finishs. """ hub = cls.get_hub() callback = kwargs.pop('callback', None) ret = func(*args, **kwargs) if concurrent.is_future(ret): if ret.done(): return ret.result() return hub.execute_future(ret, callback) else: return ret
def run() -> None: try: result = func() if result is not None: from tornado.gen import convert_yielded result = convert_yielded(result) except Exception: fut = Future() # type: Future[Any] future_cell[0] = fut future_set_exc_info(fut, sys.exc_info()) else: if is_future(result): future_cell[0] = result else: fut = Future() future_cell[0] = fut fut.set_result(result) assert future_cell[0] is not None self.add_future(future_cell[0], lambda future: self.stop())
def post(self, dev, circuit, prop): try: #print "%s-%s-%s" %(dev,circuit,prop) device = Devices.by_name(dev, circuit) kw = dict([(k, v[0]) for (k, v) in self.request.body_arguments.iteritems()]) result = device.set(**kw) if is_future(result): result = yield result #print result self.write(json.dumps({'success': True, 'result': result})) except Exception, E: self.write( json.dumps({ 'success': False, 'errors': { '__all__': str(E) } }))
def maybe_future(x): """Converts ``x`` into a `.Future`. If ``x`` is already a `.Future`, it is simply returned; otherwise it is wrapped in a new `.Future`. This is suitable for use as ``result = yield gen.maybe_future(f())`` when you don't know whether ``f()`` returns a `.Future` or not. .. deprecated:: 4.3 This function only handles ``Futures``, not other yieldable objects. Instead of `maybe_future`, check for the non-future result types you expect (often just ``None``), and ``yield`` anything unknown. """ if is_future(x): return x else: fut = _create_future() fut.set_result(x) return fut
def handle_yield(self, yielded): if isinstance(yielded, (list, dict)): yielded = Multi(yielded) if isinstance(yielded, YieldPoint): self.future = TracebackFuture() def start_yield_point(): try: yielded.start(self) if yielded.is_ready(): self.future.set_result(yielded.get_result()) else: self.yield_point = yielded except Exception: self.future = TracebackFuture() self.future.set_exc_info(sys.exc_info()) if self.stack_context_deactivate is None: # Start a stack context if this is the first # YieldPoint we've seen. with stack_context.ExceptionStackContext( self.handle_exception) as deactivate: self.stack_context_deactivate = deactivate def cb(): start_yield_point() self.run() self.io_loop.add_callback(cb) return False else: start_yield_point() elif is_future(yielded): self.future = yielded if not self.future.done() or self.future is moment: self.io_loop.add_future(self.future, lambda f: self.run()) return False else: self.future = TracebackFuture() self.future.set_exception( BadYieldError("yielded unknown object %r" % (yielded, ))) return True
def test_write_measurements_while_already_processing(self): database = str(uuid.uuid4()) name = str(uuid.uuid4()) test_value = random.randint(1000, 2000) measurement = influxdb.Measurement(database, name) measurement.set_field('test', test_value) influxdb.add_measurement(measurement) self.assertEqual(influxdb._pending_measurements(), 1) future = influxdb._on_timeout() second_write = influxdb._write_measurements() self.assertTrue(concurrent.is_future(second_write)) self.assertTrue(second_write.done()) self.assertFalse(second_write.result()) self.assertEqual(influxdb._pending_measurements(), 0) self.io_loop.add_future(future, self.stop) self.wait() result = self.get_measurement() self.assertEqual(result.db, database) self.assertEqual(result.name, name) self.assertEqual(result.fields['test'], test_value)
def execute_next(self, request, mv_type, handler, *args, **kwargs): method_name = self._call_mapper.get(mv_type) if method_name == 'process_request': middleware_list = self.middleware_list elif method_name in ['process_response', 'process_finished']: # 这两个方法的处理顺序是反序 middleware_list = self.middleware_list[-1::-1] else: return try: for mv_class in middleware_list: instance = mv_class(handler) # 如果不提供 default, 不存在时会出现异常 m = getattr(instance, method_name, None) logger.debug('%s, %s, %s' % (mv_class, m, method_name)) if m and callable(m): try: result = m(*args, **kwargs) if is_future(result): yield result except Exception as e: logger.error(e) logger.error(traceback.format_exc()) # 在某一层的中间件出现异常,下一级的都不执行 self.clear_nested_middleware(mv_class) # 如果在 request 阶段就出现了异常,直接进入 finish if mv_type == _REQUEST and not self._finished: status_code = getattr(e, 'status_code', GATEWAY_ERROR_STATUS_CODE) logger.debug('exception write error') self.write_error(status_code, exc_info=sys.exc_info()) # 不再往下执行 break except Exception as e: logger.error(e) logger.error(traceback.format_exc()) # 出现了预料之外的错误, 清理所有中间件, 结束 self.middleware_list = [] status_code = getattr(e, 'status_code', GATEWAY_ERROR_STATUS_CODE) self.write_error(status_code, exc_info=sys.exc_info())
def message_receive(self, _comm, msg): intent = msg[process_comms.INTENT_KEY] if intent == process_comms.Intent.PLAY: result = self.play() elif intent == process_comms.Intent.PAUSE: result = self.pause(msg=msg.get(process_comms.MESSAGE_KEY, None)) elif intent == process_comms.Intent.KILL: result = self.kill(msg=msg.get(process_comms.MESSAGE_KEY, None)) elif intent == process_comms.Intent.STATUS: status_info = {} self.get_status_info(status_info) result = status_info else: raise RuntimeError("Unknown intent") if concurrent.is_future(result): # Wait for the process to actually finish result = yield result raise gen.Return(result)
def convert_yielded(yielded): """Convert a yielded object into a `.Future`. The default implementation accepts lists, dictionaries, and Futures. If the `~functools.singledispatch` library is available, this function may be extended to support additional types. For example:: @convert_yielded.register(asyncio.Future) def _(asyncio_future): return tornado.platform.asyncio.to_tornado_future(asyncio_future) .. versionadded:: 4.1 """ # Lists and dicts containing YieldPoints were handled separately # via Multi(). if isinstance(yielded, (list, dict)): return multi_future(yielded) elif is_future(yielded): return yielded else: raise BadYieldError("yielded unknown object %r" % (yielded, ))