def compile(route): pattern_buf = b'' for segment in route.segments: typ = getattr(SegmentType, segment[0].upper()) pattern_buf += Segment.pack(typ, len(segment[1].encode('utf-8'))) \ + padto8(segment[1].encode('utf-8')) methods_buf = ' '.join(route.methods).encode('ascii') methods_len = len(methods_buf) if methods_buf: methods_buf += b' ' methods_len += 1 methods_buf = padto8(methods_buf) handler = route.handler if asyncio.iscoroutinefunction(handler) \ and analyzer.is_pointless_coroutine(handler): handler = analyzer.coroutine_to_func(handler) # since we save id to handler in matcher entry and this is the only # reference before INCREF-ed in matcher we store it in set to prevent # destruction retain_handlers.add(handler) return MatcherEntry.pack( id(route), id(handler), asyncio.iscoroutinefunction(handler), analyzer.is_simple(handler), len(pattern_buf), methods_len, route.placeholder_cnt) \ + pattern_buf + methods_buf
def test_coroutine_type_when_patched(self): @asyncio.coroutine def a_coroutine(): pass a_patched_coroutine = patch_is_patched()(a_coroutine) self.assertEqual(asyncio.iscoroutinefunction(a_patched_coroutine), asyncio.iscoroutinefunction(a_coroutine)) self.assertEqual(inspect.isgeneratorfunction(a_patched_coroutine), inspect.isgeneratorfunction(a_coroutine)) coro = a_coroutine() patched_coro = a_patched_coroutine() try: self.assertEqual(asyncio.iscoroutine(patched_coro), asyncio.iscoroutine(coro)) finally: run_coroutine(coro) run_coroutine(patched_coro) if not _using_await: return a_coroutine = _using_await.transform(a_coroutine) a_patched_coroutine = patch_is_patched()(a_coroutine) self.assertEqual(asyncio.iscoroutinefunction(a_patched_coroutine), asyncio.iscoroutinefunction(a_coroutine)) coro = a_coroutine() patched_coro = a_patched_coroutine() try: self.assertEqual(asyncio.iscoroutine(patched_coro), asyncio.iscoroutine(coro)) finally: run_coroutine(coro) run_coroutine(patched_coro)
def _signal_connect_mode(signal, f, defer): if isinstance(signal, aioxmpp.callbacks.SyncSignal): if not asyncio.iscoroutinefunction(f): raise TypeError( "a coroutine function is required for this signal" ) if defer: raise ValueError( "cannot use defer with this signal" ) mode = None else: if asyncio.iscoroutinefunction(f): if defer: mode = aioxmpp.callbacks.AdHocSignal.SPAWN_WITH_LOOP, (None,) else: raise TypeError( "cannot use coroutine function with this signal" " without defer" ) elif defer: mode = aioxmpp.callbacks.AdHocSignal.ASYNC_WITH_LOOP, (None,) else: mode = aioxmpp.callbacks.AdHocSignal.STRONG return mode
def start(self): """ Start the nyuki The nyuki process is terminated when this method is finished """ self.loop.add_signal_handler(SIGTERM, self.abort, SIGTERM) self.loop.add_signal_handler(SIGINT, self.abort, SIGINT) # Configure services with nyuki's configuration log.debug('Running configure for services') for name, service in self._services.all.items(): service.configure(**self._config.get(name, {})) log.debug('Done configuring') # Start services self.loop.run_until_complete(self._services.start()) # Call for setup if not asyncio.iscoroutinefunction(self.setup): log.warning('setup method must be a coroutine') self.setup = asyncio.coroutine(self.setup) self.loop.run_until_complete(self.setup()) # Main loop self.loop.run_forever() # Call for teardown if not asyncio.iscoroutinefunction(self.teardown): log.warning('teardown method must be a coroutine') self.teardown = asyncio.coroutine(self.teardown) self.loop.run_until_complete(self.teardown()) # Close everything : terminates nyuki self.loop.close()
def __init__(self, on_add_apply=None, on_add_prepare=None, on_delete_apply=None, on_delete_prepare=None): @asyncio.coroutine def prepare_noop(*args, **kwargs): pass def apply_noop(*args, **kwargs): pass self.on_add_apply = on_add_apply self.on_add_prepare = on_add_prepare self.on_delete_apply = on_delete_apply self.on_delete_prepare = on_delete_prepare for f in ('on_add_apply', 'on_delete_apply'): ref = getattr(self, f) if ref is None: setattr(self, f, apply_noop) continue if asyncio.iscoroutinefunction(ref): raise ValueError('%s cannot be a coroutine' % (f,)) for f in ('on_add_prepare', 'on_delete_prepare'): ref = getattr(self, f) if ref is None: setattr(self, f, prepare_noop) continue if not asyncio.iscoroutinefunction(ref): raise ValueError("%s must be a coroutine" % f)
def _handle_update(self, update): command = update.message.text or update.message.caption if command: if command[0] == self._command_prefix: args = command[1:].split() if '@' in args[0]: # command was directed at a specific bot, check if we are the recipient command, username = args[0].split('@', 2) if username == self.myself.username: args[0] = command else: # not directed at us, goodbye return if args[0] in self._command_handlers: if update.message.chat.type not in self._command_handlers[args[0]][0]: return if asyncio.iscoroutinefunction(self._command_handlers[args[0]][1]): asyncio.ensure_future(self._command_handlers[args[0]][1](update.message, *args[1:0])) else: call_args = (self._command_handlers[args[0]][1], update.message) + tuple(args[1:0]) self._loop.call_soon(*call_args) for handler in self._message_handlers: if asyncio.iscoroutinefunction(handler): asyncio.ensure_future(handler(update.message)) else: self._loop.call_soon(handler, update.message)
def wrapper(func): is_coro = asyncio.iscoroutinefunction(func) if not is_coro: func = asyncio.coroutine(func) decorated_coro = decorator(func) assert asyncio.iscoroutinefunction(decorated_coro) if is_coro: return decorated_coro else: # Unwrap the coroutine. We know it should never yield. @functools.wraps(decorated_coro, assigned=functools.WRAPPER_ASSIGNMENTS + EXTRA_PARAMS, updated=()) def decorated_func(*args, **kwargs): x = iter(decorated_coro(*args, **kwargs)) try: next(x) except StopIteration as e: return e.value else: raise Exception( "Decorator %s behaving badly wrapping non-coroutine %s" % (decorator.__name__, func.__name__) ) return decorated_func
def __init__(self, method, handler, *, expect_handler=None, resource=None): if expect_handler is None: expect_handler = _defaultExpectHandler assert asyncio.iscoroutinefunction(expect_handler), \ 'Coroutine is expected, got {!r}'.format(expect_handler) method = upstr(method) if method not in self.METHODS: raise ValueError("{} is not allowed HTTP method".format(method)) assert callable(handler), handler if asyncio.iscoroutinefunction(handler): pass elif inspect.isgeneratorfunction(handler): warnings.warn("Bare generators are deprecated, " "use @coroutine wrapper", DeprecationWarning) elif (isinstance(handler, type) and issubclass(handler, AbstractView)): pass else: handler = asyncio.coroutine(handler) self._method = method self._handler = handler self._expect_handler = expect_handler self._resource = resource
def test(self): val = '' def normal(): nonlocal val val = 'normal' @asyncio.coroutine def coroutine(): nonlocal val yield from asyncio.sleep(0) val = 'coroutine' @asyncio.coroutine def yielder(f): yield from f() self.assertTrue( asyncio.iscoroutinefunction(snipe.util.as_coroutine(normal))) self.assertTrue( asyncio.iscoroutinefunction(snipe.util.as_coroutine(coroutine))) self.assertTrue(asyncio.iscoroutinefunction(coroutine)) loop = asyncio.get_event_loop() self.assertEqual(val, '') loop.run_until_complete(yielder(snipe.util.as_coroutine(normal))) self.assertEqual(val, 'normal') loop.run_until_complete(yielder(snipe.util.as_coroutine(coroutine))) self.assertEqual(val, 'coroutine')
def test_asyncio_iscoroutinefunction(self, klass): with self.subTest(is_coroutine=False): mock = klass(is_coroutine=False) self.assertFalse(asyncio.iscoroutinefunction(mock)) with self.subTest(is_coroutine=False): mock = klass(is_coroutine=True) self.assertTrue(asyncio.iscoroutinefunction(mock))
def __call__(self, view): if asyncio.iscoroutinefunction(view) or asyncio.iscoroutinefunction( getattr(view, '__call__', None) ): raise ConfigurationError( 'Coroutine {} mapped to executor.'.format(view) ) view = super().__call__(view) return self.run_in_executor_view(view)
def test_generator_type_when_patched(self): def a_generator(): yield a_patched_generator = patch_is_patched()(a_generator) self.assertTrue(inspect.isgeneratorfunction(a_generator)) self.assertTrue(inspect.isgenerator(a_generator())) self.assertEqual(asyncio.iscoroutinefunction(a_patched_generator), asyncio.iscoroutinefunction(a_generator))
async def test_match_dialogflow(self): with OpsDroid() as opsdroid: action = "myaction" decorator = matchers.match_dialogflow_action(action) opsdroid.skills.append(decorator(await self.getMockSkill())) self.assertEqual(len(opsdroid.skills), 1) self.assertEqual(opsdroid.skills[0].matchers[0]["dialogflow_action"], action) self.assertTrue(asyncio.iscoroutinefunction(opsdroid.skills[0])) intent = "myIntent" decorator = matchers.match_dialogflow_intent(intent) opsdroid.skills.append(decorator(await self.getMockSkill())) self.assertEqual(len(opsdroid.skills), 2) self.assertEqual(opsdroid.skills[1].matchers[0]["dialogflow_intent"], intent) self.assertTrue(asyncio.iscoroutinefunction(opsdroid.skills[1]))
def has_coroutine(function, api=None): if six.PY3: # pragma: 2.7 no cover import asyncio if api is None: return asyncio.iscoroutinefunction(function) else: return any( asyncio.iscoroutinefunction(func) for func in ( function, api.get_request, api.get_response ) ) else: # pragma: 3 no cover return False
async def handler_coroutine(): try: if data: if asyncio.iscoroutinefunction(handler): await handler(conn, data) else: handler(conn, data) else: if asyncio.iscoroutinefunction(handler): await handler(conn) else: handler(conn) except Exception as e: conn.main_quit(_error=e)
def test_iscoroutinefunction(self): def fn(): pass self.assertFalse(asyncio.iscoroutinefunction(fn)) def fn1(): yield self.assertFalse(asyncio.iscoroutinefunction(fn1)) @asyncio.coroutine def fn2(): yield self.assertTrue(asyncio.iscoroutinefunction(fn2))
def subscribers(self, objects, provided): subscriptions = self.subscriptions(map(providedBy, objects), provided) if provided is None: result = () for subscription in subscriptions: if not asyncio.iscoroutinefunction(subscription): subscription(*objects) else: result = [] for subscription in subscriptions: if not asyncio.iscoroutinefunction(subscription): subscriber = subscription(*objects) if subscriber is not None: result.append(subscriber) return result
async def put(self, request, instid=None): content_type = request.headers.get('Content-Type', "") content_is_json = content_type.startswith('application/json') if not content_is_json: msg = 'Request must have "Content-Type: application/json" header' return json(dict(message=msg),status=520) try: data = request.json or {} except (ServerError, TypeError, ValueError, OverflowError) as exception: #current_app.logger.exception(str(exception)) return json(dict(error_code='PARAM_ERROR', error_message='Unable to decode data'),status=520) for preprocess in self.preprocess['PATCH_SINGLE']: try: if asyncio.iscoroutinefunction(preprocess): resp = await preprocess(request=request, instance_id=instid, data=data, collection_name=self.collection_name) else: resp = preprocess(request=request, instance_id=instid, data=data,collection_name=self.collection_name) if (resp is not None) and isinstance(resp, HTTPResponse): return resp # See the note under the preprocess in the get() method. if resp is not None: instid = resp except Exception as exception: return response_exception(exception) result = await self._put(request, data, instid) if result is None: return json(dict(error_code='UNKNOWN_ERROR', error_message=''),status=520) headers = {} try: for postprocess in self.postprocess['PATCH_SINGLE']: if asyncio.iscoroutinefunction(postprocess): resp = await postprocess(request=request, result=result, collection_name=self.collection_name, headers=headers) else: resp = postprocess(request=request, result=result, collection_name=self.collection_name, headers=headers) if (resp is not None) and isinstance(resp, HTTPResponse): return resp except Exception as exception: return response_exception(exception) return json(result, headers=headers, status=200)
def add_listener(self, func, name=None): """The non decorator alternative to :meth:`listen`. Parameters ----------- func : coroutine The extra event to listen to. name : Optional[str] The name of the command to use. Defaults to ``func.__name__``. Example -------- .. code-block:: python async def on_ready(): pass async def my_message(message): pass bot.add_listener(on_ready) bot.add_listener(my_message, 'on_message') """ name = func.__name__ if name is None else name if not asyncio.iscoroutinefunction(func): raise discord.ClientException('Listeners must be coroutines') if name in self.extra_events: self.extra_events[name].append(func) else: self.extra_events[name] = [func]
def __init__(self, *, logger=web_logger, loop=None, router=None, handler_factory=RequestHandlerFactory, middlewares=(), debug=False): if loop is None: loop = asyncio.get_event_loop() if router is None: router = UrlDispatcher() assert isinstance(router, AbstractRouter), router self._debug = debug self._router = router self._handler_factory = handler_factory self._finish_callbacks = [] self._loop = loop self.logger = logger for factory in middlewares: assert asyncio.iscoroutinefunction(factory), factory self._middlewares = list(middlewares) self._on_pre_signal = PreSignal() self._on_post_signal = PostSignal() self._on_response_prepare = Signal(self)
def wrapper(function: Callable) -> Callable: wrapped = function if not asyncio.iscoroutinefunction(wrapped): wrapped = asyncio.coroutine(wrapped) compiled = simplex.compile(pattern) self.routes[compiled] = (wrapped, pattern) return function
async def process_response(self, rsp): spider_name = rsp.req.spider callback = rsp.req.callback args = list(rsp.req.callback_args) spider = self.get_spider(spider_name) func = getattr(spider, callback) async def process_response_item(item): if isinstance(item, BaseRequest): item.spider = spider.name logger.debug('Find url[{}] on requset[{}] by spider[{}]'.\ format(item.url, rsp.url, spider.name)) item.group = rsp.req.group item.ref = rsp.url await self.push_req(item) elif isinstance(item, Item): await self.push_item(item) else: raise EngineError('Unknow type') if asyncio.iscoroutinefunction(func): args.append(process_response_item) await func(rsp, *args) else: items = func(rsp, *args) if items is None: return for item in items: await process_response_item(item)
def async_add_job( self, target: Callable[..., Any], *args: Any) -> Optional[asyncio.Future]: """Add a job from within the event loop. This method must be run in the event loop. target: target to call. args: parameters for method to call. """ task = None # Check for partials to properly determine if coroutine function check_target = target while isinstance(check_target, functools.partial): check_target = check_target.func if asyncio.iscoroutine(check_target): task = self.loop.create_task(target) # type: ignore elif is_callback(check_target): self.loop.call_soon(target, *args) elif asyncio.iscoroutinefunction(check_target): task = self.loop.create_task(target(*args)) else: task = self.loop.run_in_executor( # type: ignore None, target, *args) # If a task is scheduled if self._track_task and task is not None: self._pending_tasks.append(task) return task
def __init__(self, func: Callable, schema: Optional[vol.Schema], context: Optional[Context] = None) -> None: """Initialize a service.""" self.func = func self.schema = schema self.is_callback = is_callback(func) self.is_coroutinefunction = asyncio.iscoroutinefunction(func)
def wraps_with_context(func, context): """Return a wrapped partial(func, context)""" wrapped = functools.partial(func, context) wrapped = functools.wraps(func)(wrapped) if asyncio.iscoroutinefunction(func): wrapped = asyncio.coroutine(wrapped) return wrapped
def init_app(self, app): """Initialize an ``Application`` instance. Args: app (henson.base.Application): Application instance to be initialized. Raises: TypeError: If the callback isn't a coroutine. ValueError: If the delay or backoff is negative. """ super().init_app(app) if app.settings['RETRY_DELAY'] < 0: raise ValueError('The delay cannot be negative.') if app.settings['RETRY_BACKOFF'] < 0: raise ValueError('The backoff cannot be negative.') if not asyncio.iscoroutinefunction(app.settings['RETRY_CALLBACK']): raise TypeError('The retry callback is not a coroutine.') # The retry callback should be executed before all other # callbacks. This will ensure that retryable exceptions are # retried. app._callbacks['error'].insert(0, _retry)
def onMessage(self, payload, isBinary): assert isBinary # Not sure this can happen, but lets check if not self._user: self.authentication_failed() # TODO: add better validation data = msgpack.unpackb(payload, encoding='utf8') if data.get('type') == RPC: try: func = self.dispatch(data.get('method')) except NotFoundError: self.send_exception(data, 'Method does not exist') else: args = self.check_args(func, data.get('args')) try: if asyncio.iscoroutinefunction(func): value = yield from func(*args) self.send_success(data, value) else: self.send_success(data, func(*args)) except (RequestError, RpcRequestError) as error: self.send_error(data, error) except: self.send_exception(data, 'Server error') raise
def receive_message(self, msg): if isinstance(msg, Response): if msg.cseq in self._msgs[msg.method]: original_msg = self._msgs[msg.method].get(msg.cseq) transaction = self._pending[msg.method].get(msg.cseq) transaction.feed_message(msg, original_msg=original_msg) else: raise ValueError('This Response SIP message doesn\'t have Request: "%s"' % msg) else: if msg.method != 'ACK': hdrs = CIMultiDict() hdrs['Via'] = msg.headers['Via'] hdrs['CSeq'] = msg.headers['CSeq'] hdrs['Call-ID'] = msg.headers['Call-ID'] self.send_reply(status_code=200, status_message='OK', to_details=msg.to_details, from_details=msg.from_details, headers=hdrs, payload=None) for callback_info in self.callbacks[msg.method.upper()]: if asyncio.iscoroutinefunction(callback_info['callable']): fut = callback_info['callable'](*((self, msg,) + callback_info['args']), **callback_info['kwargs']) asyncio.ensure_future(fut) else: self.loop.call_soon(partial(callback_info['callable'], *((self, msg,) + callback_info['args']), **callback_info['kwargs']))
async def extract_info(self, loop, *args, on_error=None, retry_on_error=False, **kwargs): """ Runs ytdl.extract_info within the threadpool. Returns a future that will fire when it's done. If `on_error` is passed and an exception is raised, the exception will be caught and passed to on_error as an argument. """ if callable(on_error): try: return await loop.run_in_executor(self.thread_pool, functools.partial(self.unsafe_ytdl.extract_info, *args, **kwargs)) except Exception as e: # (youtube_dl.utils.ExtractorError, youtube_dl.utils.DownloadError) # I hope I don't have to deal with ContentTooShortError's if asyncio.iscoroutinefunction(on_error): asyncio.ensure_future(on_error(e), loop=loop) elif asyncio.iscoroutine(on_error): asyncio.ensure_future(on_error, loop=loop) else: loop.call_soon_threadsafe(on_error, e) if retry_on_error: return await self.safe_extract_info(loop, *args, **kwargs) else: return await loop.run_in_executor(self.thread_pool, functools.partial(self.unsafe_ytdl.extract_info, *args, **kwargs))
def middleware(request): content_type, renderer = negotiator( request, renderers, force_negotiation, ) request['selected_media_type'] = content_type response = yield from handler(request) if getattr(response, 'data', None): # Render data with the selected renderer if asyncio.iscoroutinefunction(renderer): render_result = yield from renderer(request, response.data) else: render_result = renderer(request, response.data) else: render_result = response if isinstance(render_result, web.Response): return render_result if getattr(response, 'data', None): response.body = render_result response.content_type = content_type return response
def test_async(): with patch.object(AsyncClass, 'async_method') as mock_method: self.assertTrue(iscoroutinefunction(mock_method))
def pytest_collection_modifyitems(items): for item in items: if asyncio.iscoroutinefunction(item.function): item.add_marker('asyncio')
async def handle_request(self, *args, **kwargs): """Handle an HTTP request from the client. This is the entry point of the Engine.IO application. This function returns the HTTP response to deliver to the client. Note: this method is a coroutine. """ translate_request = self._async['translate_request'] if asyncio.iscoroutinefunction(translate_request): environ = await translate_request(*args, **kwargs) else: environ = translate_request(*args, **kwargs) if self.cors_allowed_origins != []: # Validate the origin header if present # This is important for WebSocket more than for HTTP, since # browsers only apply CORS controls to HTTP. origin = environ.get('HTTP_ORIGIN') if origin: allowed_origins = self._cors_allowed_origins(environ) if allowed_origins is not None and origin not in \ allowed_origins: self._log_error_once( origin + ' is not an accepted origin.', 'bad-origin') return await self._make_response( self._bad_request( origin + ' is not an accepted origin.'), environ) method = environ['REQUEST_METHOD'] query = urllib.parse.parse_qs(environ.get('QUERY_STRING', '')) sid = query['sid'][0] if 'sid' in query else None jsonp = False jsonp_index = None # make sure the client uses an allowed transport transport = query.get('transport', ['polling'])[0] if transport not in self.transports: self._log_error_once('Invalid transport', 'bad-transport') return await self._make_response( self._bad_request('Invalid transport'), environ) # make sure the client speaks a compatible Engine.IO version sid = query['sid'][0] if 'sid' in query else None if sid is None and query.get('EIO') != ['4']: self._log_error_once( 'The client is using an unsupported version of the Socket.IO ' 'or Engine.IO protocols', 'bad-version' ) return await self._make_response(self._bad_request( 'The client is using an unsupported version of the Socket.IO ' 'or Engine.IO protocols' ), environ) if 'j' in query: jsonp = True try: jsonp_index = int(query['j'][0]) except (ValueError, KeyError, IndexError): # Invalid JSONP index number pass if jsonp and jsonp_index is None: self._log_error_once('Invalid JSONP index number', 'bad-jsonp-index') r = self._bad_request('Invalid JSONP index number') elif method == 'GET': if sid is None: # transport must be one of 'polling' or 'websocket'. # if 'websocket', the HTTP_UPGRADE header must match. upgrade_header = environ.get('HTTP_UPGRADE').lower() \ if 'HTTP_UPGRADE' in environ else None if transport == 'polling' \ or transport == upgrade_header == 'websocket': r = await self._handle_connect(environ, transport, jsonp_index) else: self._log_error_once('Invalid websocket upgrade', 'bad-upgrade') r = self._bad_request('Invalid websocket upgrade') else: if sid not in self.sockets: self._log_error_once('Invalid session ' + sid, 'bad-sid') r = self._bad_request('Invalid session ' + sid) else: socket = self._get_socket(sid) try: packets = await socket.handle_get_request(environ) if isinstance(packets, list): r = self._ok(packets, jsonp_index=jsonp_index) else: r = packets except exceptions.EngineIOError: if sid in self.sockets: # pragma: no cover await self.disconnect(sid) r = self._bad_request() if sid in self.sockets and self.sockets[sid].closed: del self.sockets[sid] elif method == 'POST': if sid is None or sid not in self.sockets: self._log_error_once('Invalid session ' + sid, 'bad-sid') r = self._bad_request('Invalid session ' + sid) else: socket = self._get_socket(sid) try: await socket.handle_post_request(environ) r = self._ok(jsonp_index=jsonp_index) except exceptions.EngineIOError: if sid in self.sockets: # pragma: no cover await self.disconnect(sid) r = self._bad_request() except: # pragma: no cover # for any other unexpected errors, we log the error # and keep going self.logger.exception('post request handler error') r = self._ok(jsonp_index=jsonp_index) elif method == 'OPTIONS': r = self._ok() else: self.logger.warning('Method %s not supported', method) r = self._method_not_found() if not isinstance(r, dict): return r if self.http_compression and \ len(r['response']) >= self.compression_threshold: encodings = [e.split(';')[0].strip() for e in environ.get('HTTP_ACCEPT_ENCODING', '').split(',')] for encoding in encodings: if encoding in self.compression_methods: r['response'] = \ getattr(self, '_' + encoding)(r['response']) r['headers'] += [('Content-Encoding', encoding)] break return await self._make_response(r, environ)
def wrap(f): # Make sure number of schemas is same as method argument args_index = 1 if hasattr(f, '_pass_app'): args_index += 1 if hasattr(f, '_job'): args_index += 1 if hasattr(f, '_skip_arg'): args_index += f._skip_arg assert len(schema) == f.__code__.co_argcount - args_index # -1 for self def clean_and_validate_args(args, kwargs): args = list(args) args = args[:args_index] + copy.deepcopy(args[args_index:]) kwargs = copy.deepcopy(kwargs) verrors = ValidationErrors() # Iterate over positional args first, excluding self i = 0 for _ in args[args_index:]: attr = nf.accepts[i] value = attr.clean(args[args_index + i]) args[args_index + i] = value try: attr.validate(value) except ValidationErrors as e: verrors.extend(e) i += 1 # Use i counter to map keyword argument to rpc positional for x in list(range(i + args_index, f.__code__.co_argcount)): kwarg = f.__code__.co_varnames[x] if kwarg in kwargs: attr = nf.accepts[i] i += 1 value = kwargs[kwarg] elif len(nf.accepts) >= i + 1: attr = nf.accepts[i] i += 1 value = NOT_PROVIDED else: i += 1 continue value = attr.clean(value) kwargs[kwarg] = value try: attr.validate(value) except ValidationErrors as e: verrors.extend(e) if verrors: raise verrors return args, kwargs if asyncio.iscoroutinefunction(f): async def nf(*args, **kwargs): args, kwargs = clean_and_validate_args(args, kwargs) return await f(*args, **kwargs) else: def nf(*args, **kwargs): args, kwargs = clean_and_validate_args(args, kwargs) return f(*args, **kwargs) nf.__name__ = f.__name__ nf.__doc__ = f.__doc__ # Copy private attrs to new function so decorators can work on top of it # e.g. _pass_app for i in dir(f): if i.startswith('__'): continue if i.startswith('_'): setattr(nf, i, getattr(f, i)) nf.accepts = list(schema) return nf
async def wrapped_function(*args, **kwargs): orig_args = list(args) args_len = len(orig_args) rt = RuntimeError( "Must only use crossdomain decorator on a function that takes 'request' as " "first or second argument") if args_len < 1: #weird, no args raise rt elif args_len < 2: request = orig_args.pop(0) args = (request, ) else: next_arg = orig_args.pop(0) args = list() if isinstance(next_arg, HTTPMethodView) or issubclass( next_arg, HTTPMethodView): args.append(next_arg) # self or cls next_arg = orig_args.pop(0) request = next_arg args.append(request) args.extend(orig_args) args = tuple(args) if not isinstance(request, sanic_request): raise rt do_await = iscoroutinefunction(f) if automatic_options and request.method == 'OPTIONS': resp = HTTPResponse() else: resp = f(*args, **kwargs) if do_await: resp = await resp if isinstance(resp, str): resp = HTTPResponse(resp) elif isinstance(resp, tuple): if len(resp) < 2: resp = HTTPResponse(resp[0]) elif len(resp) < 3: resp = HTTPResponse(resp[0], status=resp[1]) else: resp = HTTPResponse(resp[0], status=resp[1], headers=resp[2]) if not isinstance(resp, HTTPResponse): raise RuntimeError( "crossorigin wrapper did not get a valid response from the wrapped function" ) if not attach_to_all and request.method != 'OPTIONS': return resp h = resp.headers h['Access-Control-Allow-Origin'] = origin h['Access-Control-Allow-Methods'] = get_methods() h['Access-Control-Max-Age'] = str(max_age) if credentials: h['Access-Control-Allow-Credentials'] = 'true' if headers is not None: h['Access-Control-Allow-Headers'] = headers if expose_headers is not None: h['Access-Control-Expose-Headers'] = expose_headers return resp
async def _yell(fn, *args, **kwargs): if asyncio.iscoroutinefunction(fn): return await fn(*args, **kwargs) else: return fn(*args, **kwargs)
def _retry(f): @wraps(f) def _f_with_retries(*args, **kwargs): retries = 0 while True: try: return f(*args, **kwargs) except Exception as e: # If we get an exception that we're not sure about, we simply catch it and log the error in the db if type(e) not in exceptions: return RetryException(f""" Caught an unknown exception. Refraining from retries {e} """) retries += 1 if retries == max_retries: return RetryException(f""" Failed to execute {f.__name__} despite exponential backoff {e} """) else: backoff_interval = 2**retries jitter = uniform(1, 2) total_backoff = backoff_interval + jitter sys.stderr.write( f"Retrying {f.__name__} #{retries}. Sleeping for {total_backoff}s" ) sys.stderr.flush() sleep(total_backoff) @wraps(f) async def _async_f_with_retries(*args, **kwargs): retries = 0 while True: try: return await f(*args, **kwargs) except Exception as e: # If we get an exception that we're not sure about, we simply catch it and log the error in the db if type(e) not in exceptions: return RetryException(f""" Caught an unknown exception. Refraining from retries {e} """) retries += 1 if retries == max_retries: return RetryException(f""" Failed to execute {f.__name__} despite exponential backoff {e} """) else: backoff_interval = 2**retries jitter = uniform(1, 2) total_backoff = backoff_interval + jitter sys.stderr.write( f"Retrying {f.__name__} #{retries}. Sleeping for {total_backoff}s" ) sys.stderr.flush() asyncio.sleep(total_backoff) if asyncio.iscoroutinefunction(f): return _async_f_with_retries else: return _f_with_retries
def test_is_task(self): assert callable(move.move) assert isinstance(move.move, celery.Task) assert not asyncio.iscoroutine(move.move) assert asyncio.iscoroutinefunction(move.move.adelay)
def test_iscoroutinefunction_default(self): mock = AsyncMock() self.assertTrue(iscoroutinefunction(mock))
def is_coroutine_function(f): return asyncio.iscoroutinefunction(f) or gen.is_coroutine_function(f)
async def _publish_loop(self): """ Start a loop that sends a publish requests and waits for the publish responses. Forward the `PublishResult` to the matching `Subscription` by callback. """ ack = None while True: try: response = await self.publish([ack] if ack else []) except BadTimeout: # See Spec. Part 4, 7.28 # Repeat without acknowledgement ack = None continue except BadNoSubscription: # See Spec. Part 5, 13.8.1 # BadNoSubscription is expected to be received after deleting the last subscription. # We use this as a signal to exit this task and stop sending PublishRequests. This is easier then # checking if there are no more subscriptions registered in this client (). A Publish response # could still arrive before the DeleteSubscription response. # # We could remove the callback already when sending the DeleteSubscription request, # but there are some legitimate reasons to keep them around, such as when the server # responds with "BadTimeout" and we should try again later instead of just removing # the subscription client-side. # # There are a variety of ways to act correctly, but the most practical solution seems # to be to just silently ignore any BadNoSubscription responses. self.logger.info( "BadNoSubscription received, ignoring because it's probably valid." ) # End task return except UaStructParsingError: ack = None continue subscription_id = response.Parameters.SubscriptionId if not subscription_id: # The value 0 is used to indicate that there were no Subscriptions defined for which a # response could be sent. See Spec. Part 4 - Section 5.13.5 "Publish" # End task return try: callback = self._subscription_callbacks[subscription_id] except KeyError: self.logger.warning( "Received data for unknown subscription %s active are %s", subscription_id, self._subscription_callbacks.keys()) else: try: if asyncio.iscoroutinefunction(callback): await callback(response.Parameters) else: callback(response.Parameters) except Exception: # we call user code, catch everything! self.logger.exception( "Exception while calling user callback: %s") # Repeat with acknowledgement if response.Parameters.NotificationMessage.NotificationData: ack = ua.SubscriptionAcknowledgement() ack.SubscriptionId = subscription_id ack.SequenceNumber = response.Parameters.NotificationMessage.SequenceNumber else: ack = None
def test_iscoroutinefunction(self): async def foo(): pass self.assertTrue(asyncio.iscoroutinefunction(foo))
async def message_loop(self, handler=None, relax=0.1, timeout=20, allowed_updates=None, source=None, ordered=True, maxhold=3): """ Return a task to constantly ``getUpdates`` or pull updates from a queue. Apply ``handler`` to every message received. :param handler: a function that takes one argument (the message), or a routing table. If ``None``, the bot's ``handle`` method is used. A *routing table* is a dictionary of ``{flavor: function}``, mapping messages to appropriate handler functions according to their flavors. It allows you to define functions specifically to handle one flavor of messages. It usually looks like this: ``{'chat': fn1, 'callback_query': fn2, 'inline_query': fn3, ...}``. Each handler function should take one argument (the message). :param source: Source of updates. If ``None``, ``getUpdates`` is used to obtain new messages from Telegram servers. If it is a ``asyncio.Queue``, new messages are pulled from the queue. A web application implementing a webhook can dump updates into the queue, while the bot pulls from it. This is how telepot can be integrated with webhooks. Acceptable contents in queue: - ``str`` or ``bytes`` (decoded using UTF-8) representing a JSON-serialized `Update <https://core.telegram.org/bots/api#update>`_ object. - a ``dict`` representing an Update object. When ``source`` is a queue, these parameters are meaningful: :type ordered: bool :param ordered: If ``True``, ensure in-order delivery of messages to ``handler`` (i.e. updates with a smaller ``update_id`` always come before those with a larger ``update_id``). If ``False``, no re-ordering is done. ``handler`` is applied to messages as soon as they are pulled from queue. :type maxhold: float :param maxhold: Applied only when ``ordered`` is ``True``. The maximum number of seconds an update is held waiting for a not-yet-arrived smaller ``update_id``. When this number of seconds is up, the update is delivered to ``handler`` even if some smaller ``update_id``\s have not yet arrived. If those smaller ``update_id``\s arrive at some later time, they are discarded. :type timeout: int :param timeout: ``timeout`` parameter supplied to :meth:`telepot.aio.Bot.getUpdates`, controlling how long to poll in seconds. :type allowed_updates: array of string :param allowed_updates: ``allowed_updates`` parameter supplied to :meth:`telepot.aio.Bot.getUpdates`, controlling which types of updates to receive. """ if handler is None: handler = self.handle elif isinstance(handler, dict): handler = flavor_router(handler) def create_task_for(msg): self.loop.create_task(handler(msg)) if asyncio.iscoroutinefunction(handler): callback = create_task_for else: callback = handler def handle(update): try: key = _find_first_key(update, [ 'message', 'edited_message', 'channel_post', 'edited_channel_post', 'callback_query', 'inline_query', 'chosen_inline_result', 'shipping_query', 'pre_checkout_query' ]) callback(update[key]) except: # Localize the error so message thread can keep going. traceback.print_exc() finally: return update['update_id'] async def get_from_telegram_server(): offset = None # running offset allowed_upd = allowed_updates while 1: try: result = await self.getUpdates(offset=offset, timeout=timeout, allowed_updates=allowed_upd) # Once passed, this parameter is no longer needed. allowed_upd = None if len(result) > 0: # No sort. Trust server to give messages in correct order. # Update offset to max(update_id) + 1 offset = max([handle(update) for update in result]) + 1 except CancelledError: raise except exception.BadHTTPResponse as e: traceback.print_exc() # Servers probably down. Wait longer. if e.status == 502: await asyncio.sleep(30) except: traceback.print_exc() await asyncio.sleep(relax) else: await asyncio.sleep(relax) def dictify(data): if type(data) is bytes: return json.loads(data.decode('utf-8')) elif type(data) is str: return json.loads(data) elif type(data) is dict: return data else: raise ValueError() async def get_from_queue_unordered(qu): while 1: try: data = await qu.get() update = dictify(data) handle(update) except: traceback.print_exc() async def get_from_queue(qu): # Here is the re-ordering mechanism, ensuring in-order delivery of updates. max_id = None # max update_id passed to callback buffer = collections.deque( ) # keep those updates which skip some update_id qwait = None # how long to wait for updates, # because buffer's content has to be returned in time. while 1: try: data = await asyncio.wait_for(qu.get(), qwait) update = dictify(data) if max_id is None: # First message received, handle regardless. max_id = handle(update) elif update['update_id'] == max_id + 1: # No update_id skipped, handle naturally. max_id = handle(update) # clear contagious updates in buffer if len(buffer) > 0: buffer.popleft( ) # first element belongs to update just received, useless now. while 1: try: if type(buffer[0]) is dict: max_id = handle( buffer.popleft() ) # updates that arrived earlier, handle them. else: break # gap, no more contagious updates except IndexError: break # buffer empty elif update['update_id'] > max_id + 1: # Update arrives pre-maturely, insert to buffer. nbuf = len(buffer) if update['update_id'] <= max_id + nbuf: # buffer long enough, put update at position buffer[update['update_id'] - max_id - 1] = update else: # buffer too short, lengthen it expire = time.time() + maxhold for a in range(nbuf, update['update_id'] - max_id - 1): buffer.append( expire) # put expiry time in gaps buffer.append(update) else: pass # discard except asyncio.TimeoutError: # debug message # print('Timeout') # some buffer contents have to be handled # flush buffer until a non-expired time is encountered while 1: try: if type(buffer[0]) is dict: max_id = handle(buffer.popleft()) else: expire = buffer[0] if expire <= time.time(): max_id += 1 buffer.popleft() else: break # non-expired except IndexError: break # buffer empty except: traceback.print_exc() finally: try: # don't wait longer than next expiry time qwait = buffer[0] - time.time() if qwait < 0: qwait = 0 except IndexError: # buffer empty, can wait forever qwait = None # debug message # print ('Buffer:', str(buffer), ', To Wait:', qwait, ', Max ID:', max_id) self._scheduler._callback = callback if source is None: await get_from_telegram_server() elif isinstance(source, asyncio.Queue): if ordered: await get_from_queue(source) else: await get_from_queue_unordered(source) else: raise ValueError('Invalid source')
def test_is_async_AsyncMock(self): mock = AsyncMock(spec_set=AsyncClass.async_method) self.assertTrue(iscoroutinefunction(mock)) self.assertIsInstance(mock, AsyncMock)
async def async_handler(*args): if asyncio.iscoroutinefunction(handler): return await handler(*args) else: return handler(*args)
async def call_sync_async(call, *args, **kwargs): is_coroutine = asyncio.iscoroutinefunction(call) if is_coroutine: return await call(*args, **kwargs) else: return await run_in_threadpool(call, *args, **kwargs)
def run(self, namespace: dict, id: int = None, looping_interval: float = 0.05, ignore_exceptions=False, offline=False, debug=False): """ Runs the main event loop. This function must be called only once. It should be placed on the last line of the robot's script because this function does not return. :param dict namespace: The global namespace (technically, the namespace \ that contains :func:`setup()` and :func:`loop()`) the robot program. \ This is what makes all the magic happen. If you have \ no idea what it is, use :func:`globals()`. :param id: The robot's ID. If the program is running on an robotics \ lab's Raspberry Pi, it is automatically calculated. This is not \ necessary if the robot is operating under offline mode. :param float looping_interval: Looping interval \ in seconds. Defaults to :code`0.05` (that is, the loop runs 20 times per \ second). :param bool ignore_exceptions: Whether or not the robot should continue \ running if an exception occurs when the loop is running. Note that it\ does not mean the program will continue executing the next line, but\ will run the next iteration of the loop instead. Defaults to :code:`False`.\ It is dangerous to enable and use only if you are confident that your\ program can recover from unhandled exceptions. Regardless of this value,\ KeyboardInterrupt (ctrl-c) will always shutdown the robot. :param bool offline: Whether the robot should operate offline. That is,\ if offline is set to True, the robot will not attempt to connect to the \ network. You also don't have to supply a robot ID if this is set to True. :param bool debug: Whether to enable debugging mode or not, default to \ False. This will enable the verbose mode, good to enable if you ever \ wonder what's going on inside the robot. """ if debug: self._logger.setLevel(logging.DEBUG) self._logger.info('Initializing the robot...') if offline: self._logger.info('Running under offline mode.') self.id = 0 else: self._logger.debug( "Attempting to deduct robot's ID from hostname...") hostname = socket.gethostname() match = re.fullmatch(r'^choate-robotics-rpi-(\d{2})$', hostname) if match: self.id = int(match.group(1)) self._logger.debug("Calculated ID is %d." % self.id) else: if isinstance(id, int): self._logger.debug( "Cannot calculate ID. Using user supplied ID %d." % id) self.id = id else: raise ValueError( "ID cannot be calculated. Please specify an ID.") self._event_loop = asyncio.get_event_loop() self._event_loop.set_exception_handler(self._exception_handler) self._should_stop = asyncio.Event() self._exit_code = 0 self._ignore_exceptions = False self._debug = debug self.__globals = namespace self._looping_interval = looping_interval self._ignore_exceptions = ignore_exceptions signal.signal(signal.SIGTERM, self._signal_handler) signal.signal(signal.SIGINT, self._signal_handler) signal.signal(signal.SIGQUIT, self._signal_handler) if 'setup' in self.__globals: self._setup = self.__globals['setup'] self._logger.debug( 'Setup function collected from the user namespace.') else: self._setup = noop self._logger.debug( 'Setup function not found in the user namespace. Using noop.') if asyncio.iscoroutinefunction(self._setup): print('Setup function must not be async') sys.exit(1) if not offline: self._logger.info('Attempting to connect to the RobotNetwork...') self.network.connect() if self.network.is_connected: self._logger.info('Connected to the network') self._logger.debug('Running setup.') self._run_setup() if 'on_message' in self.__globals: self._on_message = self.__globals['on_message'] self._logger.debug( 'Message handler collected from the user namespace.') else: self._on_message = noop self._logger.debug( "Message handler not found in the user namespace. Using noop.") if 'on_shutdown' in self.__globals: self._on_shutdown = self.__globals['on_shutdown'] self._logger.debug( 'Shutdown handler collected from the user namespace.') else: self._on_shutdown = noop self._logger.debug( "Shutdown handler not found in the user namespace. Using noop." ) if 'loop' in self.__globals: self._loop = self.__globals['loop'] self._logger.debug( 'Loop function collected from the user namespace.') else: self._loop = noop self._logger.debug( "Loop function not found in the user namespace. Using noop.") if asyncio.iscoroutinefunction(self._loop): asyncio.ensure_future(self._run_loop_async()) else: self._event_loop.call_soon(self._run_loop) self._logger.debug('Loop runner scheduled.') if not offline: asyncio.ensure_future(self._poll()) self._logger.debug('Polling scheduled.') try: self._event_loop.set_debug(self._debug) self._logger.debug('Starting the event loop...') self._event_loop.run_forever() finally: self._logger.info("Shutting down the robot...") try: self._logger.debug("Running final cleanup.") self._event_loop.run_until_complete(self._shutdown()) finally: try: # retrieve all CancelledError self._event_loop.run_until_complete( asyncio.gather(*asyncio.Task.all_tasks())) except asyncio.CancelledError: pass self._logger.debug('Event loop closed.') self._event_loop.close() self._logger.debug("Robot exit.") logging.shutdown() sys.exit(self._exit_code)
def __call__(self, method: Callable) -> Callable: """Caller for the throttle.""" # Make sure we return a coroutine if the method is async. if asyncio.iscoroutinefunction(method): async def throttled_value() -> None: """Stand-in function for when real func is being throttled.""" return None else: def throttled_value() -> None: # type: ignore """Stand-in function for when real func is being throttled.""" return None if self.limit_no_throttle is not None: method = Throttle(self.limit_no_throttle)(method) # Different methods that can be passed in: # - a function # - an unbound function on a class # - a method (bound function on a class) # We want to be able to differentiate between function and unbound # methods (which are considered functions). # All methods have the classname in their qualname separated by a '.' # Functions have a '.' in their qualname if defined inline, but will # be prefixed by '.<locals>.' so we strip that out. is_func = (not hasattr(method, '__self__') and '.' not in method.__qualname__.split('.<locals>.')[-1]) @wraps(method) def wrapper(*args: Any, **kwargs: Any) -> Union[Callable, Coroutine]: """Wrap that allows wrapped to be called only once per min_time. If we cannot acquire the lock, it is running so return None. """ # pylint: disable=protected-access if hasattr(method, '__self__'): host = getattr(method, '__self__') elif is_func: host = wrapper else: host = args[0] if args else wrapper if not hasattr(host, '_throttle'): host._throttle = {} if id(self) not in host._throttle: host._throttle[id(self)] = [threading.Lock(), None] throttle = host._throttle[id(self)] if not throttle[0].acquire(False): return throttled_value() # Check if method is never called or no_throttle is given force = kwargs.pop('no_throttle', False) or not throttle[1] try: if force or utcnow() - throttle[1] > self.min_time: result = method(*args, **kwargs) throttle[1] = utcnow() return result # type: ignore return throttled_value() finally: throttle[0].release() return wrapper
def f(*args, **kwargs): if asyncio.iscoroutinefunction(func): loop = asyncio.new_event_loop() # loop in a new thread loop.run_until_complete(func(*args, **kwargs)) else: func(*args, **kwargs)
"""`Coroutine` providers example with @asyncio.coroutine decorator. Current example works only fot Python 3.4+. """ import asyncio import dependency_injector.providers as providers @asyncio.coroutine def coroutine_function(arg1, arg2): """Sample coroutine function.""" yield from asyncio.sleep(0.1) return arg1, arg2 coroutine_provider = providers.Coroutine(coroutine_function, arg1=1, arg2=2) if __name__ == '__main__': loop = asyncio.get_event_loop() arg1, arg2 = loop.run_until_complete(coroutine_provider()) assert (arg1, arg2) == (1, 2) assert asyncio.iscoroutinefunction(coroutine_provider)
def decorator(func: T) -> T: nonlocal params, action_name params = params or {} missing_intrinsics = list(set(intrinsic_params) - set(params.keys())) if missing_intrinsics: raise Exception( f"Intrinsic parameter names {missing_intrinsics} do not refer to any params of action {action_name}'s" f" decorator") params = params or {} if action_name is None: match = re.match('^action_(?P<name>.+)$', func.__name__) if not match: raise Exception( "Could not automatically discern action name, or at least" "no the form of 'action_XXX'") matches = match.groupdict() action_name = matches['name'] func_parameters = inspect.signature(func).parameters provided = list(func_parameters.keys()) has_kwargs = len( list( filter(lambda p: p.kind == inspect.Parameter.VAR_KEYWORD, func_parameters.values()))) > 0 is_coro = asyncio.iscoroutinefunction(func) # kwargs is a catch all so don't be strict about parameters if they have it if not has_kwargs: required = set(params.keys()) missing_params = list(required - set(provided)) if missing_params: raise Exception( 'Callable {func!r} does not provide required params: {missing_params!r}' ) action = Action( instance=None, name=action_name, func=func, func_params=provided, params=params, intrinsic_params=list(intrinsic_params), is_coro=is_coro, has_kwargs=has_kwargs, exclusive_async=exclusive_async, timeout=timeout, ) setattr(func, Action.func_attr_tag, action) return func
def start_coroutine(func): loop = asyncio.get_event_loop() if asyncio.iscoroutinefunction(func): pass else: loop.call_soon_threadsafe(func)
def __init__(self, func: Callable): self.func = func self.batch_func = None self.is_async = asyncio.iscoroutinefunction(self.func)
def __init__(self, anonymous_handler): if not iscoroutinefunction(anonymous_handler): raise TypeError( "AnonymousReceiveMiddleware must be instantiated with a valid coroutine function." ) self._to_call = anonymous_handler
async def _encrypt(self, stanza: StanzaBase) -> Optional[StanzaBase]: if not isinstance(stanza, Message) or stanza['type'] not in ( 'normal', 'chat', 'groupchat'): raise NothingToEncrypt() message = stanza # Find who to encrypt to. If in a groupchat this can be multiple JIDs. # It is possible that we are not able to find a jid (e.g., semi-anon # MUCs). Let the plugin decide what to do with this information. jids = [message['to']] # type: Optional[List[JID]] tab = self.core.tabs.by_jid(message['to']) if tab is None: # When does that ever happen? log.debug( 'Attempting to encrypt a message to \'%s\' ' 'that is not attached to a Tab. ?! Aborting ' 'encryption.', message['to']) return None parent = None if isinstance(tab, PrivateTab): parent = tab.parent_muc nick = tab.jid.resource jids = None for user in parent.users: if user.nick == nick: jids = user.jid or None break if isinstance(tab, MucTab): jids = [] for user in tab.users: # If the JID of a user is None, assume all others are None and # we are in a (at least) semi-anon room. TODO: Really check if # the room is semi-anon. Currently a moderator of a semi-anon # room will possibly encrypt to everybody, leaking their # public key/identity, and they wouldn't be able to decrypt it # anyway if they don't know the moderator's JID. # TODO: Change MUC to give easier access to this information. if user.jid is None: jids = None break # If we encrypt to all of these JIDs is up to the plugin, we # just tell it who is in the room. # XXX: user.jid shouldn't be empty. That's a MucTab/slixmpp # bug. if user.jid.bare: jids.append(user.jid) if not self._encryption_enabled(tab.jid): raise NothingToEncrypt() log.debug('Sending %s message', self.encryption_name) has_body = message.xml.find('{%s}%s' % (JCLIENT_NS, 'body')) is not None # Drop all messages that don't contain a body if the plugin doesn't do # Stanza Encryption if not self.stanza_encryption and not has_body: log.debug( '%s plugin: Dropping message as it contains no body, and ' 'not doesn\'t do stanza encryption', self.encryption_name, ) return None # Call the enabled encrypt method func = self._enabled_tabs[tab.jid] if iscoroutinefunction(func): # pylint: disable=unexpected-keyword-arg await func(message, jids, tab, passthrough=True) else: # pylint: disable=unexpected-keyword-arg func(message, jids, tab, passthrough=True) if has_body: # Only add EME tag if the message has a body. # Per discussion in jdev@: # The receiving client needs to know the message contains # meaningful information or not to display notifications to the # user, and not display anything when it's e.g., a chatstate. # This does leak the fact that the encrypted payload contains a # message. message['eme']['namespace'] = self.eme_ns message['eme']['name'] = self.encryption_name if self.replace_body_with_eme: self.core.xmpp['xep_0380'].replace_body_with_eme(message) # Filter stanza with the whitelist. Plugins doing stanza encryption # will have to include these in their encrypted container beforehand. whitelist = self.tag_whitelist if self.encrypted_tags is not None: whitelist += self.encrypted_tags tag_whitelist = {'{%s}%s' % tag for tag in whitelist} for elem in message.xml[:]: if elem.tag not in tag_whitelist: message.xml.remove(elem) log.debug('Encrypted %s message', self.encryption_name) return message
async def _folder_file_op(self, func: typing.Callable, dest_provider: 'BaseProvider', src_path: wb_path.WaterButlerPath, dest_path: wb_path.WaterButlerPath, **kwargs) -> typing.Tuple[wb_metadata.BaseFolderMetadata, bool]: """Recursively apply func to src/dest path. Called from: func: copy and move if src_path.is_dir. Calls: func: dest_provider.delete and notes result for bool: created func: dest_provider.create_folder func: dest_provider.revalidate_path func: self.metadata :param coroutine func: to be applied to src/dest path :param *Provider dest_provider: Destination provider :param *ProviderPath src_path: Source path :param *ProviderPath dest_path: Destination path """ assert src_path.is_dir, 'src_path must be a directory' assert asyncio.iscoroutinefunction(func), 'func must be a coroutine' try: await dest_provider.delete(dest_path) created = False except exceptions.ProviderError as e: if e.code != 404: raise created = True folder = await dest_provider.create_folder(dest_path, folder_precheck=False) dest_path = await dest_provider.revalidate_path(dest_path.parent, dest_path.name, folder=dest_path.is_dir) folder.children = [] items = await self.metadata(src_path) # type: ignore # Metadata returns a union, which confuses mypy self.provider_metrics.append('_folder_file_ops.item_counts', len(items)) # type: ignore for i in range(0, len(items), wb_settings.OP_CONCURRENCY): # type: ignore futures = [] for item in items[i:i + wb_settings.OP_CONCURRENCY]: # type: ignore futures.append(asyncio.ensure_future( func( dest_provider, # TODO figure out a way to cut down on all the requests made here (await self.revalidate_path(src_path, item.name, folder=item.is_folder)), (await dest_provider.revalidate_path(dest_path, item.name, folder=item.is_folder)), handle_naming=False, ) )) if item.is_folder: await futures[-1] if not futures: continue done, _ = await asyncio.wait(futures, return_when=asyncio.FIRST_EXCEPTION) for fut in done: folder.children.append(fut.result()[0]) return folder, created
def as_future(self, fun, *args, **kwargs): # Twisted doesn't automagically deal with coroutines on Py3 if PY3_CORO and iscoroutinefunction(fun): return ensureDeferred(fun(*args, **kwargs)) return maybeDeferred(fun, *args, **kwargs)
def gather(*coros_or_futures, limit=0, loop=None, timeout=None, preserve_order=False, return_exceptions=False): """ Return a future aggregating results from the given coroutine objects with a concurrency execution limit. If all the tasks are done successfully, the returned future’s result is the list of results (in the order of the original sequence, not necessarily the order of results arrival). If return_exceptions is `True`, exceptions in the tasks are treated the same as successful results, and gathered in the result list; otherwise, the first raised exception will be immediately propagated to the returned future. All futures must share the same event loop. This functions is mostly compatible with Python standard ``asyncio.gather``, but providing ordered results and concurrency control flow. This function is a coroutine. Arguments: *coros_or_futures (coroutines|list): an iterable collection yielding coroutines functions or futures. limit (int): max concurrency limit. Use ``0`` for no limit. timeout can be used to control the maximum number of seconds to wait before returning. timeout can be an int or float. If timeout is not specified or None, there is no limit to the wait time. preserve_order (bool): preserves results order. return_exceptions (bool): returns exceptions as valid results. loop (asyncio.BaseEventLoop): optional event loop to use. Returns: list: coroutines returned results. Usage:: async def sum(x, y): return x + y await paco.gather( sum(1, 2), sum(None, 'str'), return_exceptions=True) # => [3, TypeError("unsupported operand type(s) for +: 'NoneType' and 'str'")] # noqa """ # If no coroutines to schedule, return empty list (as Python stdlib) if len(coros_or_futures) == 0: return [] # Support iterable as first argument for better interoperability if len(coros_or_futures) == 1 and isiter(coros_or_futures[0]): coros_or_futures = coros_or_futures[0] # Pre-initialize results results = [None] * len(coros_or_futures) if preserve_order else [] # Create concurrent executor pool = ConcurrentExecutor(limit=limit, loop=loop) # Iterate and attach coroutine for defer scheduling for index, coro in enumerate(coros_or_futures): # Validate coroutine object if asyncio.iscoroutinefunction(coro): coro = coro() if not asyncio.iscoroutine(coro): raise TypeError( 'paco: only coroutines or coroutine functions allowed') # Add coroutine to the executor pool pool.add(collect(coro, index, results, preserve_order=preserve_order, return_exceptions=return_exceptions)) # Wait until all the tasks finishes yield from pool.run(timeout=timeout, return_exceptions=return_exceptions) # Returns aggregated results return results
def test_async(mock_method): self.assertTrue(iscoroutinefunction(mock_method))
def _dispatch_callback(self, key: str) -> None: callback = self._callbacks[key] if asyncio.iscoroutinefunction(callback): asyncio.create_task(callback()) else: callback()