def decorate(func, caller, extras=()): """ decorate(func, caller) decorates a function using a caller. If the caller is a generator function, the resulting function will be a generator function. """ evaldict = dict(_call_=caller, _func_=func) es = '' for i, extra in enumerate(extras): ex = '_e%d_' % i evaldict[ex] = extra es += ex + ', ' if '3.5' <= sys.version < '3.6': # with Python 3.5 isgeneratorfunction returns True for all coroutines # however we know that it is NOT possible to have a generator # coroutine in python 3.5: PEP525 was not there yet generatorcaller = isgeneratorfunction( caller) and not iscoroutinefunction(caller) else: generatorcaller = isgeneratorfunction(caller) if generatorcaller: fun = FunctionMaker.create( func, "for res in _call_(_func_, %s%%(shortsignature)s):\n" " yield res" % es, evaldict, __wrapped__=func) else: fun = FunctionMaker.create( func, "return _call_(_func_, %s%%(shortsignature)s)" % es, evaldict, __wrapped__=func) if hasattr(func, '__qualname__'): fun.__qualname__ = func.__qualname__ return fun
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 main(): print isgeneratorfunction(numList) for num in numList(10): print num for content in read_file('../README.md'): print content
def openFile(self, filePath, cursorPosition = None, focus = True, mainWindow = None, useTasks = True): """Open a editor in current window""" filePath = self.fileManager.normcase(filePath) if self.fileManager.isOpen(filePath): mainWindow, editor = self.findEditorForFile(filePath) if editor is not None: mainWindow.setCurrentEditor(editor) if isinstance(cursorPosition, tuple): editor.setCursorPosition(cursorPosition) elif self.fileManager.exists(filePath): mainWindow = mainWindow or self.mainWindow editor = self.createEditorInstance(filePath, mainWindow) def on_editorReady(mainWindow, editor, cursorPosition, focus): def editorReady(openResult): if isinstance(cursorPosition, tuple): editor.setCursorPosition(cursorPosition) mainWindow.tryCloseEmptyEditor() mainWindow.addEditor(editor, focus) return editorReady if useTasks and inspect.isgeneratorfunction(editor.open): task = self.scheduler.newTask( editor.open(filePath) ) task.done.connect( on_editorReady(mainWindow, editor, cursorPosition, focus) ) elif inspect.isgeneratorfunction(editor.open): on_editorReady(mainWindow, editor, cursorPosition, focus)(list(editor.open(filePath))) else: on_editorReady(mainWindow, editor, cursorPosition, focus)(editor.open(filePath))
def object(self, obj_id): if isinstance(obj_id, six.string_types): if obj_id.startswith('st__'): # a string literal return obj_id[4:] if obj_id in self._objs: return self._objs[obj_id] if obj_id not in self._rec: raise GlueSerializeError("Unrecognized object %s" % obj_id) if obj_id in self._working: raise GlueSerializeError("Circular Reference detected: %s" % obj_id) self._working.add(obj_id) rec = self._rec[obj_id] elif isinstance(obj_id, literals) or isinstance(obj_id, (tuple, list)): return obj_id else: rec = obj_id func = self._dispatch(rec) try: obj = func(rec, self) if hasattr(obj, '__setgluestate_callback__'): self._callbacks.append(obj.__setgluestate_callback__) # loader functions might yield the constructed value, # and then futher populate it. This deals with circular # dependencies. if isgeneratorfunction(func): gen, obj = obj, next(obj) # get the partially-constructed value... if isinstance(obj_id, six.string_types): # ... add it to the registry ... self._objs[obj_id] = obj self._working.remove(obj_id) if isgeneratorfunction(func): for _ in gen: # ... and finish constructing it pass finally: # If anything in the try: block above fails, we need to remove the # obj_id from te list of IDs we are currently working on, as we # may want to try again (this happens when using the callbacks below) if isinstance(obj_id, six.string_types) and obj_id in self._working: self._working.remove(obj_id) self._try_callbacks() return obj
def parameter_wrapper(target): # Annotated Class if inspect.isclass(target): webmodules = [] for name, method in inspect.getmembers(target(), inspect.ismethod): # Checking whether the method is exposed to called from # web in the Class try: method_webname = method.__webname__ except: if name == '__call__': method_webname = "" else: continue invoker = ClassMethodInvoker(name, target) if len(method_webname) == 0: url = parameter else: url = parameter + method_webname if parameter.endswith("/") \ else parameter + "/" + method_webname webmodules.append({ "url": url, "func": invoker, "handler": method, "type": "file" if inspect.isgeneratorfunction(method) else "json", "arguments": utils.get_signature_details(method), "desc": target.__doc__ }) target.__webmodules__ = webmodules # Annotated function elif inspect.isfunction(target): target.__webmodule__ = { "url": parameter, "func": FunctionInvoker(target), "handler": target, "type": "file" if inspect.isgeneratorfunction(target) else "json", "arguments": utils.get_signature_details(target), "desc": target.__doc__ } else: raise Exception("Not implemented to support " + str(type(target))) return target
def pre_process_extensions(self, extensions, request, action_args): # List of callables for post-processing extensions post = [] for ext in extensions: if inspect.isgeneratorfunction(ext): response = None # If it's a generator function, the part before the # yield is the preprocessing stage try: with ResourceExceptionHandler(): gen = ext(req=request, **action_args) response = gen.next() except Fault as ex: response = ex # We had a response... if response: return response, [] # No response, queue up generator for post-processing post.append(gen) else: # Regular functions only perform post-processing post.append(ext) # Run post-processing in the reverse order return None, reversed(post)
def wizcmd(func): """ Public decorator to define a wizard command function. It adds a privilege check wrapper and checks the signature. Can be used by the user that is writing story code. """ func.enable_notify_action = False # none of the wizard commands should be used with notify_action func.is_tale_command_func = True # NOTE: this code is VERY similar to the internal @wizcmd decorator in cmds/wizard.py # If changes are made, make sure to update both occurrences @functools.wraps(func) def executewizcommand(player, parsed, ctx): if "wizard" not in player.privileges: raise errors.SecurityViolation("Wizard privilege required for verb " + parsed.verb) return func(player, parsed, ctx) if inspect.isgeneratorfunction(func): func.is_generator = True # contains async yields argspec = inspect.getargspec(func) if argspec.args == ["player", "parsed", "ctx"] and argspec.varargs is None and argspec.keywords is None and argspec.defaults is None: func.__doc__ = util.format_docstring(func.__doc__) return executewizcommand else: raise SyntaxError("invalid wizcmd function signature for: " + func.__name__)
def dispatch_item_single(self, item): """ Given a JSON item received from socket, determine its type and process the message. """ assert type(item) is dict item.setdefault("id", None) if "method" in item: method, args, kw = self._extract_params(item) obj = self._find_object(method, args, kw) if obj is None: return fn = self._find_method(obj, method, args, kw) try: if inspect.isgeneratorfunction(fn): for response in fn(*args, **kw): self._send_response(item, response) elif callable(fn): self._send_response(item, fn(*args, **kw)) elif fn: self._send_error(item, fn) except ServerError as exc: self._send_error(item, str(exc)) except Exception: err = self._format_exception(obj, method, args, kw, sys.exc_info()) self._send_error(item, err) elif "result" in item: assert item["id"] in self._requests request = self._requests[item["id"]] request.setresponse(item) else: self._send_error(item, "Unknown format") return True
def wrapper(self, mess, args): # Some clients automatically convert consecutive dashes into a fancy # hyphen, which breaks long-form arguments. Undo this conversion to # provide a better user experience. args = shlex.split(args.replace('—', '--')) try: parsed_args = err_command_parser.parse_args(args) except ArgumentParseError as e: yield "I'm sorry, I couldn't parse that; %s" % e yield err_command_parser.format_usage() return except HelpRequested: yield err_command_parser.format_help() return if unpack_args: func_args = [] func_kwargs = vars(parsed_args) else: func_args = [parsed_args] func_kwargs = {} if inspect.isgeneratorfunction(func): for reply in func(self, mess, *func_args, **func_kwargs): yield reply else: yield func(self, mess, *func_args, **func_kwargs)
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 run(self, module, task, response): """ Processing the task, catching exceptions and logs, return a `ProcessorResult` object """ logger = module.logger result = None exception = None stdout = sys.stdout self.task = task self.response = response try: sys.stdout = ListO(module.log_buffer) if inspect.isgeneratorfunction(self._run): for result in self._run(task, response): self._run_func(self.on_result, result, response, task) else: result = self._run(task, response) self._run_func(self.on_result, result, response, task) except Exception as e: logger.exception(e) exception = e finally: self.task = None self.response = None sys.stdout = stdout follows = self._follows messages = self._messages logs = list(module.log_buffer) extinfo = self._extinfo module.log_buffer[:] = [] return ProcessorResult(result, follows, messages, logs, exception, extinfo)
def make_cleanup(func): if inspect.isgeneratorfunction(func): @functools.wraps(func) def wrapped_callable(*args, **kwargs): original_units_registry = matplotlib.units.registry.copy() original_settings = mpl.rcParams.copy() matplotlib.style.use(style) try: for yielded in func(*args, **kwargs): yield yielded finally: _do_cleanup(original_units_registry, original_settings) else: @functools.wraps(func) def wrapped_callable(*args, **kwargs): original_units_registry = matplotlib.units.registry.copy() original_settings = mpl.rcParams.copy() matplotlib.style.use(style) try: func(*args, **kwargs) finally: _do_cleanup(original_units_registry, original_settings) return wrapped_callable
def decorator(func): if inspect.isgeneratorfunction(func): raise ConfigureError( 'Cannot decorate generator functions with @depends') func, glob = self._prepare_function(func) depends = DependsFunction(self, func, dependencies, when=when) return depends.sandboxed
def map_doc(self, doc): """run all map functions on a document""" _set_vs(self, ["emit", "log"]) results = [] for func in self.map_funcs: self._clear_state() try: if inspect.isgeneratorfunction(func): for y in func(doc): self.emit(*y) else: func(doc) except: results.append([]) self.exception("map_runtime_error", fatal=False, doc_id=doc["_id"], func=func) else: results.append(self.emissions) _set_vs(None) self._clear_state() self.output(*results)
def loadCommands(self): commands = {} path = yield self.config.get("path","commands") for loader, name, ispkg in pkgutil.iter_modules([path]): if ispkg: continue try: command = getattr(__import__(path, fromlist=[name.encode("utf8")]), name) reload(command) command.config["name"] = name command.config["command"] = coroutine(command.command) if inspect.isgeneratorfunction(command.command) else command.command args, varg, vkwarg, kwargs = inspect.getargspec(command.command) if args[:5] != ["guid", "manager", "irc", "channel", "user"]: continue if kwargs: boundary = -1 * len(kwargs) command.config["args"] = args[5:boundary] command.config["kwargs"] = args[boundary:] else: command.config["args"] = args[5:] command.config["kwargs"] = [] command.config["varg"] = varg command.config["vkwarg"] = vkwarg if "disabled" in command.config and command.config["disabled"]: continue commands[name] = command.config except: self.err("Failed to load {}.{}", path, name) self.commands = commands
def tcp_server(server_prog, *, family=socket.AF_INET, addr=None, timeout=5, backlog=1, max_clients=10): if addr is None: if family == socket.AF_UNIX: with tempfile.NamedTemporaryFile() as tmp: addr = tmp.name else: addr = ('127.0.0.1', 0) if not inspect.isgeneratorfunction(server_prog): raise TypeError('server_prog: a generator function was expected') sock = socket.socket(family, socket.SOCK_STREAM) if timeout is None: raise RuntimeError('timeout is required') if timeout <= 0: raise RuntimeError('only blocking sockets are supported') sock.settimeout(timeout) try: sock.bind(addr) sock.listen(backlog) except OSError as ex: sock.close() raise ex srv = Server(sock, server_prog, timeout, max_clients) return srv
def coroutine(function): if inspect.isgeneratorfunction(function): routine = function else: @functools.wraps(function) def routine(*args, **kwargs): # calls the underlying function with the expected arguments # and keyword arguments (proper call propagation) result = function(*args, **kwargs) # verifies the data type of the resulting object so that a # proper yielding operation or return will take place is_future_ = is_future(result) is_generator = inspect.isgenerator(result) # in case the returned value is either a future or a generator # the complete set of yielded elements are propagated and # the result is stored as the "new" result if is_future_ or is_generator: result = yield from result # returns the "final" result to the caller method as expected # this allows generated propagation return result @functools.wraps(function) def wrapper(*args, **kwargs): generator = routine(*args, **kwargs) awaitable = AwaitWrapper(generator) return awaitable wrapper._is_coroutine = True return wrapper
def _execute_and_send(self, cmd, args, match, mess, template_name=None): """Execute a bot command and send output back to the caller cmd: The command that was given to the bot (after being expanded) args: Arguments given along with cmd match: A re.MatchObject if command is coming from a regex-based command, else None mess: The message object template_name: The name of the jinja template which should be used to render the markdown output, if any """ private = cmd in self.bot_config.DIVERT_TO_PRIVATE commands = self.re_commands if match else self.commands try: if inspect.isgeneratorfunction(commands[cmd]): replies = commands[cmd](mess, match) if match else commands[cmd](mess, args) for reply in replies: if reply: self.send_simple_reply(mess, self.process_template(template_name, reply), private) else: reply = commands[cmd](mess, match) if match else commands[cmd](mess, args) if reply: self.send_simple_reply(mess, self.process_template(template_name, reply), private) except Exception as e: tb = traceback.format_exc() log.exception('An error happened while processing ' 'a message ("%s"): %s"' % (mess.body, tb)) self.send_simple_reply(mess, self.MSG_ERROR_OCCURRED + ':\n %s' % e, private)
def _create_future(self, func, args, kwargs, filtered_args_dict, should_submit): if not func.version_info['ignore_deps']: # TODO: Check a map of possible dependencies executed for # this run here, in case a depdency just got changed. This # should be done by consulting a pickled on-file database # AFAICT. raise NotImplementedError('Please use ignore_deps for now') # Make job_path containing hashes h = NumpyHasher('sha1') h.hash((func.version_info['digest'], filtered_args_dict)) job_name = '%s-%s' % (func.__name__, self._encode_digest(h._hash.digest())) # Construct job dir if not existing. Remember that we may # race for this; if we got to create the directory, we have # the lock. we_made_it = self._ensure_job_dir(job_name, func, args, kwargs) is_generator = inspect.isgenerator(func) or inspect.isgeneratorfunction(func) future = self._create_future_from_job_dir(job_name, is_generator) if we_made_it: self.logger.info('Created job: %s' % job_name) if should_submit: jobid = future.submit() self.logger.info('Submitted job as %s: %s' % (jobid, job_name)) else: self.logger.info('Job already exists: %s' % job_name) return future
def task(function): '''Thread-safe decorator to run a ``function`` in an event loop. :param function: a callable which can return coroutines, :class:`.asyncio.Future` or synchronous data. Can be a method of an :ref:`async object <async-object>`, in which case the loop is given by the object ``_loop`` attribute. :return: a :class:`~asyncio.Future` ''' if isgeneratorfunction(function): wrapper = function else: @coroutine def wrapper(*args, **kw): res = function(*args, **kw) if isawaitable(res): res = yield from res return res @wraps(function) def _(*args, **kwargs): loop = getattr(args[0], '_loop', None) if args else None coro = wrapper(*args, **kwargs) return ensure_future(coro, loop=loop) return _
def coroutine(func): """Decorator to mark coroutines. If the coroutine is not yielded from before it is destroyed, an error message is logged. """ if inspect.isgeneratorfunction(func): coro = func else: @functools.wraps(func) def coro(*args, **kw): res = func(*args, **kw) if isinstance(res, futures.Future) or inspect.isgenerator(res): res = yield from res return res if not _DEBUG: wrapper = coro else: @functools.wraps(func) def wrapper(*args, **kwds): w = CoroWrapper(coro(*args, **kwds), func) if w._source_traceback: del w._source_traceback[-1] w.__name__ = func.__name__ if hasattr(func, '__qualname__'): w.__qualname__ = func.__qualname__ w.__doc__ = func.__doc__ return w wrapper._is_coroutine = True # For iscoroutinefunction(). return wrapper
def setcallable(self, key, function, *args): if key not in self.keyValues: if inspect.isgeneratorfunction(function): self.keyValues[key] = list(function(*args)) else: self.keyValues[key] = function(*args) return self.keyValues[key]
def coroutine(func): """ Mark a function as a compatible coroutine. A compatible coroutine can be used on both Python 2 and Python 3. The corresponding coroutine object can be turned into a future using :class:`.Task`. Compatible coroutines are written using :func:`.Return` and :func:`.From`, in a similar way to Trollius. """ if inspect.isgeneratorfunction(func): coro = func else: @functools.wraps(func) def coro(*args, **kw): res = func(*args, **kw) if False: yield raise Return(res) # We could potentially add a flag to the returned coroutine object here, to # be checked by `Task` however for now this decorator just serves as # documentation. coro._is_compat_coroutine = True return coro
def wrapper(self, msg, args): # Attempt to sanitize arguments of bad characters try: sanitizer_re = re.compile('|'.join(re.escape(ii) for ii in ARG_BOTCMD_CHARACTER_REPLACEMENTS)) args = sanitizer_re.sub(lambda mm: ARG_BOTCMD_CHARACTER_REPLACEMENTS[mm.group()], args) args = shlex.split(args) parsed_args = err_command_parser.parse_args(args) except ArgumentParseError as e: yield "I'm sorry, I couldn't parse the arguments; %s" % e yield err_command_parser.format_usage() return except HelpRequested: yield err_command_parser.format_help() return except ValueError as ve: yield "I'm sorry, I couldn't parse this command; %s" % ve yield err_command_parser.format_help() return if unpack_args: func_args = [] func_kwargs = vars(parsed_args) else: func_args = [parsed_args] func_kwargs = {} if inspect.isgeneratorfunction(func): for reply in func(self, msg, *func_args, **func_kwargs): yield reply else: yield func(self, msg, *func_args, **func_kwargs)
def __init__(self, func): func = get_function_object(func) code = get_code_object(func) pysig = utils.pysignature(func) if not code: raise errors.ByteCodeSupportError( "%s does not provide its bytecode" % func) # A map of {offset: ByteCodeInst} table = utils.SortedMap(ByteCodeIter(code)) labels = set(dis.findlabels(code.co_code)) labels.add(0) try: func_qualname = func.__qualname__ except AttributeError: func_qualname = func.__name__ self._mark_lineno(table, code) super(ByteCode, self).__init__(func=func, func_qualname=func_qualname, is_generator=inspect.isgeneratorfunction(func), pysig=pysig, filename=code.co_filename, co_names=code.co_names, co_varnames=code.co_varnames, co_consts=code.co_consts, co_freevars=code.co_freevars, table=table, labels=list(sorted(labels)))
def inner(*args, **kwargs): """ Wrap func to check if we've already entered this function and if so replace it with a no-op. """ def generator(): """ Hide the generator in a separate function because Python 2 can't support "returning from generators" """ if entered[0]: yield else: try: entered[0] = True for val in func(*args, **kwargs): yield val finally: entered[0] = False if inspect.isgeneratorfunction(func): return generator() else: if not entered[0]: try: entered[0] = True return func(*args, **kwargs) finally: entered[0] = False
def isgenerator(func): if PYTHON_VERSION_MAJOR == 3: return inspect.isgeneratorfunction(func) try: return func.func_code.co_flags & CO_GENERATOR != 0 except AttributeError: return False
def decorator( method: Callable[..., Generator[T, None, R]], ) -> Callable[..., Generator[T, None, R]]: assert isgeneratorfunction(method) @wraps(method) def wrapper( self: Any, target: Target, *args: Any, _seen_targets: Optional[Set[Target]] = None, **kwargs: Any ) -> Any: if _seen_targets is None: _seen_targets = set() if skip_check is None: checking = True else: checking = not skip_check(self, target, *args, **kwargs) if checking: if target in _seen_targets: raise DriverError(f"Cycle detected from {target}") else: _seen_targets.add(target) try: return ( yield from method( self, target, *args, _seen_targets=_seen_targets, **kwargs ) ) finally: if checking: _seen_targets.discard(target) return wrapper
def tsv_extractor(generator): """ When a generator function is decorated with this (i.e., @tsv_extractor preceding the def line), standard input is parsed as Postgres-style TSV (PGTSV) input rows, the function is applied to generate output rows, and then checks that each line of this generator is in the output format before printing back as PGTSV rows. """ # Expects the input and output formats to have been decorated with @over and @returns try: # @over has precedence over default values of function arguments input_format = generator.input_format except AttributeError: input_format = format_from_args_defaults_of(generator) try: output_format = generator.output_format # also support function argument defaults for output_format for symmetry output_format = format_from_args_defaults_of(output_format) except AttributeError: raise ValueError("The function must be decorated with @returns") # TODO or maybe just skip type checking if @returns isn't present? # Check generator function if not isgeneratorfunction(generator): raise ValueError("The function must be a *generator*, i.e., use yield not return") # Create the input parser parser = PGTSVParser(input_format) # Create the output parser printer = PGTSVPrinter(output_format) for row in parser.parse_stdin(): for out_row in generator(**row._asdict()): printer.write(out_row)
def decorator(func): if inspect.isgeneratorfunction(func): func = inlineCallbacks(func) self._signals.setdefault(name, []).append(func) return func
def decorate_callable(self, func): if hasattr(func, 'patchings'): func.patchings.append(self) return func is_generator_func = inspect.isgeneratorfunction(func) is_coroutine_func = asyncio.iscoroutinefunction(func) if not (is_generator_func or is_coroutine_func): return super().decorate_callable(func) @functools.wraps(func) def patched(*args, **keywargs): extra_args = [] entered_patchers = [] exc_info = tuple() try: for patching in patched.patchings: arg = patching.__enter__() entered_patchers.append(patching) if patching.attribute_name is not None: keywargs.update(arg) if patching.new is DEFAULT: patching.new = arg[patching.attribute_name] elif patching.new is DEFAULT: patching.new = arg extra_args.append(arg) args += tuple(extra_args) gen = func(*args, **keywargs) return _PatchedGenerator(gen, patched.patchings, asyncio.iscoroutinefunction(func)) except: if patching not in entered_patchers and unittest.mock._is_started( patching): # the patcher may have been started, but an exception # raised whilst entering one of its additional_patchers entered_patchers.append(patching) # Pass the exception to __exit__ exc_info = sys.exc_info() # re-raise the exception raise finally: for patching in reversed(entered_patchers): patching.__exit__(*exc_info) patched.patchings = [self] if is_generator_func: # wrap the patched object in a generator so # inspect.isgeneratorfunction() returns True @functools.wraps(func) def patched_generator(*args, **kwargs): return (yield from patched(*args, **kwargs)) if is_coroutine_func: return asyncio.coroutine(patched_generator) else: return patched_generator else: return functools.wraps(func)(patched)
def signature(cls, f): r"""Construct a Signature object describing `f` Compute a Signature so that we can write a function wrapping f with the same signature and call-type. Parameters ---------- f : callable A function to be decorated Returns ------- sig : argmap.Signature The Signature of f Notes ----- The Signature is a namedtuple with names: name : a unique version of the name of the decorated function signature : the inspect.signature of the decorated function def_sig : a string used as code to define the new function call_sig : a string used as code to call the decorated function names : a dict keyed by argument name and index to the argument's name n_positional : the number of positional arguments in the signature args : the name of the VAR_POSITIONAL argument if any, i.e. \*theseargs kwargs : the name of the VAR_KEYWORDS argument if any, i.e. \*\*kwargs These named attributes of the signature are used in `assemble` and `compile` to construct a string of source code for the decorated function. """ sig = inspect.signature(f, follow_wrapped=False) def_sig = [] call_sig = [] names = {} kind = None args = None kwargs = None npos = 0 for i, param in enumerate(sig.parameters.values()): # parameters can be position-only, keyword-or-position, keyword-only # in any combination, but only in the order as above. we do edge # detection to add the appropriate punctuation prev = kind kind = param.kind if prev == param.POSITIONAL_ONLY != kind: # the last token was position-only, but this one isn't def_sig.append("/") if prev != param.KEYWORD_ONLY == kind != param.VAR_POSITIONAL: # param is the first keyword-only arg and isn't starred def_sig.append("*") # star arguments as appropriate if kind == param.VAR_POSITIONAL: name = "*" + param.name args = param.name count = 0 elif kind == param.VAR_KEYWORD: name = "**" + param.name kwargs = param.name count = 0 else: names[i] = names[param.name] = param.name name = param.name count = 1 # assign to keyword-only args in the function call if kind == param.KEYWORD_ONLY: call_sig.append(f"{name} = {name}") else: npos += count call_sig.append(name) def_sig.append(name) fname = cls._name(f) def_sig = f'def {fname}({", ".join(def_sig)}):' if inspect.isgeneratorfunction(f): _return = "yield from" else: _return = "return" call_sig = f"{_return} {{}}({', '.join(call_sig)})" return cls.Signature(fname, sig, def_sig, call_sig, names, npos, args, kwargs)
import asyncio, os, inspect, logging, functools
def construct(self, data=None): """ Construct the expression(s) for this logical constraint. """ generate_debug_messages = \ __debug__ and logger.isEnabledFor(logging.DEBUG) if generate_debug_messages: logger.debug("Constructing logical constraint list %s" % self.name) if self._constructed: return self._constructed = True assert self._init_expr is None _init_rule = self.rule # # We no longer need these # self._init_expr = None # Utilities like DAE assume this stays around # self.rule = None if _init_rule is None: return _generator = None _self_parent = self._parent() if inspect.isgeneratorfunction(_init_rule): _generator = _init_rule(_self_parent) elif inspect.isgenerator(_init_rule): _generator = _init_rule if _generator is None: while True: val = len(self._index) + 1 if generate_debug_messages: logger.debug( " Constructing logical constraint index " + str(val)) expr = apply_indexed_rule(self, _init_rule, _self_parent, val) if expr is None: raise ValueError( "LogicalConstraintList '%s': rule returned None " "instead of LogicalConstraintList.End" % (self.name,)) if (expr.__class__ is tuple) and \ (expr == LogicalConstraintList.End): return self.add(expr) else: for expr in _generator: if expr is None: raise ValueError( "LogicalConstraintList '%s': generator returned None " "instead of LogicalConstraintList.End" % (self.name,)) if (expr.__class__ is tuple) and \ (expr == LogicalConstraintList.End): return self.add(expr)
def __init__(self, func: Callable, frame=None, args: tuple = None, kwargs: Dict[str, Any] = None, forward_refs_policy=ForwardRefPolicy.ERROR): self.func = func self.func_name = function_name(func) self.signature = inspect.signature(func) self.typevars = {} # type: Dict[Any, type] self.is_generator = isgeneratorfunction(func) if args is not None and kwargs is not None: self.arguments = self.signature.bind(*args, **kwargs).arguments else: assert frame, 'frame must be specified if args or kwargs is None' self.arguments = frame.f_locals.copy() self.type_hints = _type_hints_map.get(func) if self.type_hints is None: while True: try: hints = get_type_hints(func) except NameError as exc: if forward_refs_policy is ForwardRefPolicy.ERROR: raise typename = str(exc).split("'", 2)[1] for param in self.signature.parameters.values(): if param.annotation == typename: break else: raise func_name = function_name(func) if forward_refs_policy is ForwardRefPolicy.GUESS: if param.name in self.arguments: argtype = self.arguments[param.name].__class__ if param.annotation == argtype.__qualname__: func.__annotations__[param.name] = argtype msg = ( 'Replaced forward declaration {!r} in {} with {!r}' .format(param.annotation, func_name, argtype)) warn(TypeHintWarning(msg)) continue msg = 'Could not resolve type hint {!r} on {}: {}'.format( param.annotation, function_name(func), exc) warn(TypeHintWarning(msg)) del func.__annotations__[param.name] else: break self.type_hints = OrderedDict() for name, parameter in self.signature.parameters.items(): if name in hints: annotated_type = hints[name] # PEP 428 discourages it by MyPy does not complain if parameter.default is None: annotated_type = Optional[annotated_type] if parameter.kind == Parameter.VAR_POSITIONAL: self.type_hints[name] = Tuple[annotated_type, ...] elif parameter.kind == Parameter.VAR_KEYWORD: self.type_hints[name] = Dict[str, annotated_type] else: self.type_hints[name] = annotated_type if 'return' in hints: self.type_hints['return'] = hints['return'] _type_hints_map[func] = self.type_hints
def decorator(func): """Decorator for the given function.""" tries = retries + 1 is_generator = inspect.isgeneratorfunction(func) function_with_type = function if is_generator: function_with_type += ' (generator)' def handle_retry(num_try, exception=None): """Handle retry.""" if (exception is None or isinstance( exception, exception_type)) and num_try < tries: logs.info('Retrying on %s failed with %s. Retrying again.', function_with_type, sys.exc_info()[1]) sleep(get_delay(num_try, delay, backoff)) return True logs.error('Retrying on %s failed with %s. Raise.', function_with_type, sys.exc_info()[1]) return False @functools.wraps(func) def _wrapper(*args, **kwargs): """Regular function wrapper.""" for num_try in range(1, tries + 1): try: result = func(*args, **kwargs) if retry_on_false and not result: if not handle_retry(num_try): return result continue return result except Exception as error: # pylint: disable=broad-except if not handle_retry(num_try, exception=error): raise @functools.wraps(func) def _generator_wrapper(*args, **kwargs): """Generator function wrapper.""" # This argument is not applicable for generator functions. assert not retry_on_false already_yielded_element_count = 0 for num_try in range(1, tries + 1): try: for index, result in enumerate(func(*args, **kwargs)): if index >= already_yielded_element_count: yield result already_yielded_element_count += 1 break except Exception as error: # pylint: disable=broad-except if not handle_retry(num_try, exception=error): raise if is_generator: return _generator_wrapper return _wrapper
def str_file(func, **kwargs): """A decorator to automatically open arguments that are files. If there are kwargs then they are name=mode. When the function is called if the argument name is a string then the file is opened with mode. If there are no kwargs then it is assumed the first argument is a file that should be opened as 'r' """ possible_files = kwargs # We need to have the generator check out here so that the inner function is # either a generator (has a yield) or not. If we were to try to have this if # inside of the open_files then we would always return a generator. if inspect.isgeneratorfunction(func): @six.wraps(func) def open_files(*args, **kwargs): # If no arg names are given then assume the first arg is a file # you want to read from. if not possible_files: if isinstance(args[0], six.string_types): with io.open(args[0], mode='r', encoding='utf-8') as f: # Call the function with the file instead we need to # yield from it until it is done other wise the file # will be closed after the first yield. for x in func(f, *args[1:], **kwargs): yield x else: for x in func(*args, **kwargs): yield x else: # Otherwise we have multiple files we want to open to_close = [] # Get a dict representation of what it will look like if we # call func with *args and **kwargs arg = inspect.getcallargs(func, *args, **kwargs) try: for f, mode in possible_files.items(): if isinstance(arg[f], six.string_types): # Replace strings with the opened files arg[f] = io.open(arg[f], mode=mode, encoding='utf-8') to_close.append(f) # Call the function with the files instead for x in func(**arg): yield x finally: # Make sure to close the files for f in to_close: arg[f].close() else: @six.wraps(func) def open_files(*args, **kwargs): # If no arg names are given then assume the first arg is a file # you want to read from. if not possible_files: if isinstance(args[0], six.string_types): with io.open(args[0], mode='r', encoding='utf-8') as f: # Call the function with the file instead return func(f, *args[1:], **kwargs) else: return func(*args, **kwargs) else: # Otherwise we have multiple files we want to open to_close = [] # Get a dict representation of what it will look like if we # call func with *args and **kwargs arg = inspect.getcallargs(func, *args, **kwargs) try: for f, mode in possible_files.items(): if isinstance(arg[f], six.string_types): # Replace strings with the opened files arg[f] = io.open(arg[f], mode=mode, encoding='utf-8') to_close.append(f) # Call the function with the files instead return func(**arg) finally: # Make sure to close the files for f in to_close: arg[f].close() return open_files
def coroutine(func): """Decorator to mark coroutines. If the coroutine is not yielded from before it is destroyed, an error message is logged. """ if _inspect_iscoroutinefunction(func): # In Python 3.5 that's all we need to do for coroutines # defiend with "async def". # Wrapping in CoroWrapper will happen via # 'sys.set_coroutine_wrapper' function. return func if inspect.isgeneratorfunction(func): coro = func else: @_wraps(func) def coro(*args, **kw): res = func(*args, **kw) if (isinstance(res, futures._FUTURE_CLASSES) or inspect.isgenerator(res)): res = yield From(res) elif _AwaitableABC is not None: # If 'func' returns an Awaitable (new in 3.5) we # want to run it. try: await_meth = res.__await__ except AttributeError: pass else: if isinstance(res, _AwaitableABC): res = yield From(await_meth()) raise Return(res) if _PEP479: # FIXME: use @_wraps coro = pep479_wrapper(func, coro) coro = _wraps(func)(coro) if not _DEBUG: if _types_coroutine is None: wrapper = coro else: wrapper = _types_coroutine(coro) else: @_wraps(func) def wrapper(*args, **kwds): w = CoroWrapper(coro(*args, **kwds), func=func) if w._source_traceback: del w._source_traceback[-1] # Python < 3.5 does not implement __qualname__ # on generator objects, so we set it manually. # We use getattr as some callables (such as # functools.partial may lack __qualname__). w.__name__ = getattr(func, '__name__', None) w.__qualname__ = getattr(func, '__qualname__', None) return w wrapper._is_coroutine = True # For iscoroutinefunction(). return wrapper
assert bool(type(CompiledClass.compiledMethod) == types.MethodType) == ( sys.version_info < (3, )) print("Compiled method:", inspect.getargspec(CompiledClass().compiledMethod)) print( "Compiled class:", inspect.formatargspec(*inspect.getargspec(CompiledClass().compiledMethod))) def compiledGenerator(): yield 1 assert inspect.isfunction(compiledGenerator) is True assert inspect.isgeneratorfunction(compiledGenerator) is True assert isinstance(compiledGenerator(), types.GeneratorType) is True assert type(compiledGenerator()) == types.GeneratorType assert isinstance(compiledGenerator, types.GeneratorType) is False assert inspect.ismethod(compiledGenerator()) is False assert inspect.isfunction(compiledGenerator()) is False assert inspect.isgenerator(compiledFunction) is False assert inspect.isgenerator(compiledGenerator) is False assert inspect.isgenerator(compiledGenerator()) is True def someFunction(a): assert inspect.isframe(sys._getframe())
def pytest_pycollect_makeitem(collector, name, obj): if collector.funcnamefilter(name) and inspect.isgeneratorfunction(obj): item = pytest.Function(name, parent=collector) if 'gen_test' in item.keywords: return list(collector._genfunctions(name, obj))
def decorate_with_data(routine): # passthrough an already decorated routine: # (could this be any uglier?) if hasattr(routine, 'setup'): def passthru_setup(): routine.setup() if setup: setup() else: passthru_setup = setup if hasattr(routine, 'teardown'): def passthru_teardown(): routine.teardown() if teardown: teardown() else: passthru_teardown = teardown def setup_data(): data = self.data(*datasets) data.setup() return data def teardown_data(data): data.teardown() @wraps(routine) def call_routine(*a,**kw): data = setup_data() try: routine(data, *a, **kw) except KeyboardInterrupt: # user wants to abort everything : raise except Exception as exc: # caught exception, so try to teardown but do it safely : try: teardown_data(data) except: t_ident = ("-----[exception in teardown %s]-----" % hex(id(teardown_data))) sys.stderr.write("\n\n%s\n" % t_ident) traceback.print_exc() sys.stderr.write("%s\n\n" % t_ident) reraise(exc.__class__, exc) else: teardown_data(data) @wraps(routine) def iter_routine(): for stack in routine(): fn = stack[0] try: args = stack[1:] except IndexError: args = tuple([]) def atomic_routine(*genargs,**kw): setup_data = genargs[0] data = setup_data() try: genargs = genargs[1:] except IndexError: genargs = tuple([]) genargs = (data,) + genargs try: fn(*genargs, **kw) except Exception as exc: try: teardown_data(data) except: t_ident = ( "-----[exception in teardown %s]-----" % hex(id(teardown_data))) sys.stderr.write("\n\n%s\n" % t_ident) traceback.print_exc() sys.stderr.write("%s\n\n" % t_ident) reraise(exc.__class__, exc) else: teardown_data(data) restack = (atomic_routine, setup_data) + args yield restack if isgeneratorfunction(routine): wrapped_routine = iter_routine else: wrapped_routine = call_routine decorate = with_setup( setup=passthru_setup, teardown=passthru_teardown ) return decorate( wrapped_routine )
from collections.abc import Iterable import types def fab(max): n, a, b = 0, 0, 1 while n < max: yield (b) # 使用yield #print(b) a, b = b, a + b n = n + 1 # fab是生成器函数,而fab(10)是调用fab函数返回的一个生成器 # 好比类的定义和类的实例的区别 # fab() if isgeneratorfunction(fab): print("fab is a generator function") if isinstance(fab, Iterable) == False: print('fab is not iterable') print("") # fab(10) if isinstance(fab(10), types.GeneratorType): print("fab(10) is a instance") if isinstance(fab(10), Iterable) == True: print('fab(10) is iterable')
def is_generator(obj): return callable(obj) and (isgeneratorfunction(obj) or isgeneratorfunction(getattr(obj, '__call__')))
async def _negotiate(self, initiator): """ (*Coroutine*) Handle the establishment of the WebRTC peer connection. """ ice_servers = [ RTCIceServer('stun:stun.l.google.com:19302'), RTCIceServer('stun:stun2.l.google.com:19302'), RTCIceServer('stun:stunserver.org:3478') ] self._pc = RTCPeerConnection(RTCConfiguration(ice_servers)) async def add_datachannel_listeners(): """ Set the listeners to handle data channel events """ @self._datachannel.on('message') async def on_message(message): try: data = json.loads(message) except: raise TypeError('Received an invalid json message data') self._data = data try: for handler in self._data_handlers: if inspect.iscoroutinefunction(handler): await handler(data) else: handler(data) except Exception as e: logging.exception(e, traceback.format_exc()) raise e @self._datachannel.on('close') async def on_close(): if self.readyState == PeerState.CONNECTED: logging.info('Datachannel lost, disconnecting...') self.disconnection_event.set() @self._datachannel.on('error') async def on_error(error): logging.error('Datachannel error: ' + str(error)) self.disconnection_event.set() @self._pc.on('track') def on_track(track): """ Set the consumer or destination of the incomming video and audio tracks """ logging.info('Track %s received' % track.kind) if track.kind == 'audio': #webrtc_connection.addTrack(player.audio) #recorder.addTrack(track) pass elif track.kind == 'video': #local_video = VideoTransformTrack(track, transform=signal['video_transform']) #webrtc_connection.addTrack(local_video) if self._frame_consumer_feeder: self._track_consumer_task = asyncio.create_task( self._frame_consumer_feeder.feed_with(track)) @track.on('ended') async def on_ended(): logging.info('Remote track %s ended' % track.kind) if self.readyState == PeerState.CONNECTED: logging.info('Remote media track ended, disconnecting...') self.disconnection_event.set() #await recorder.stop() @self._pc.on('iceconnectionstatechange') async def on_iceconnectionstatechange(): """ Monitor the ICE connection state """ logging.info('ICE connection state of peer (%s) is %s', self.id, self._pc.iceConnectionState) if self._pc.iceConnectionState == 'failed': self.disconnection_event.set() elif self._pc.iceConnectionState == 'completed': # self._set_readyState(PeerState.CONNECTED) pass # Add media tracks if self._media_source: if self._media_source_format: self._player = MediaPlayer(self._media_source, format=self._media_source_format) else: self._player = MediaPlayer(self._media_source) if self._player.audio: self._pc.addTrack(self._player.audio) if self._player.video: self._pc.addTrack(self._player.video) @self._player.video.on('ended') async def on_ended(): logging.info('Local track %s ended' % self._player.video.kind) if self.readyState == PeerState.CONNECTED: logging.info('disconnecting...') self.disconnection_event.set() logging.info('Video player track added') elif self._frame_generator: if inspect.isgeneratorfunction(self._frame_generator): self._pc.addTrack( FrameGeneratorTrack(self._frame_generator, frame_rate=self._frame_rate)) logging.info('Video frame generator track added') else: logging.info('No video track to add') if initiator: logging.info('Initiating peer connection...') do = self._datachannel_options if do: self._datachannel = self._pc.createDataChannel( do['label'], do['maxPacketLifeTime'], do['maxRetransmits'], do['ordered'], do['protocol']) else: self._datachannel = self._pc.createDataChannel('data_channel') await self._pc.setLocalDescription(await self._pc.createOffer()) signal = { 'sdp': self._pc.localDescription.sdp, 'type': self._pc.localDescription.type } await self._send(signal) signal = await self._get_signal() if signal['type'] != 'answer': raise Exception('Expected answer from remote peer', signal) answer = RTCSessionDescription(sdp=signal['sdp'], type=signal['type']) await self._pc.setRemoteDescription(answer) @self._datachannel.on('open') async def on_open(): self._set_readyState(PeerState.CONNECTED) await add_datachannel_listeners() pass #asyncio.ensure_future(send_pings()) else: logging.info('Waiting for peer connection...') @self._pc.on('datachannel') async def on_datachannel(channel): self._datachannel = channel self._set_readyState(PeerState.CONNECTED) await add_datachannel_listeners() signal = await self._get_signal() if signal['type'] != 'offer': raise Exception('Expected offer from remote peer', signal) offer = RTCSessionDescription(sdp=signal['sdp'], type=signal['type']) await self._pc.setRemoteDescription(offer) answer = await self._pc.createAnswer() await self._pc.setLocalDescription(answer) answer = { 'sdp': self._pc.localDescription.sdp, 'type': self._pc.localDescription.type } await self._send(answer) logging.info('starting _handle_candidates_task...') self._handle_candidates_task = asyncio.create_task( self._handle_ice_candidates()) logging.info('sending local ice candidates...') # ice_servers = RTCIceGatherer.getDefaultIceServers() logging.debug(f'ice_servers: {ice_servers}') ice_gatherer = RTCIceGatherer(ice_servers) local_candidates = ice_gatherer.getLocalCandidates() logging.debug(f'local_candidates: {local_candidates}') for candidate in local_candidates: sdp = ( f"{candidate.foundation} {candidate.component} {candidate.protocol} " f"{candidate.priority} {candidate.ip} {candidate.port} typ {candidate.type}" ) if candidate.relatedAddress is not None: sdp += f" raddr {candidate.relatedAddress}" if candidate.relatedPort is not None: sdp += f" rport {candidate.relatedPort}" if candidate.tcpType is not None: sdp += f" tcptype {candidate.tcpType}" message = { "candidate": "candidate:" + sdp, "id": candidate.sdpMid, "label": candidate.sdpMLineIndex, "type": "candidate", } logging.info(message) await self._send(message) while self.readyState == PeerState.CONNECTING: await asyncio.sleep(0.2) if self._track_consumer_task: logging.info('starting _remote_track_monitor_task...') self._remote_track_monitor_task = asyncio.create_task( self._remote_track_monitor()) self._connection_monitor_task = asyncio.create_task( self._connection_monitor())
def _producer_iter(self): """A little helper to also support generator functions""" return self.producer() if inspect.isgeneratorfunction( self.producer) else self.producer
def is_gen_callable(call: Callable) -> bool: if inspect.isgeneratorfunction(call): return True call = getattr(call, "__call__", None) return inspect.isgeneratorfunction(call)
def __init__(self, frame_generator): if not inspect.isgeneratorfunction(frame_generator): raise TypeError('frame_generator should be a generator function') super().__init__() # don't forget this! self.generator = frame_generator() self.last_time = time.time()
#!/usr/bin/env python3 # -*- coding: utf-8 -*- # 斐波那契数列 # F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2) def fab_with_yield(mx): x, y, n = 0, 1, 1 while n < mx: yield y x, y = y, x + y n += 1 def test(): for i in fab_with_yield(5): print(i) test() from inspect import isgeneratorfunction print(isgeneratorfunction(fab_with_yield)) from collections import Iterable print(isinstance(fab_with_yield, Iterable)) print(isinstance(fab_with_yield(5), Iterable))
def _format_coroutine(coro): assert iscoroutine(coro) if not hasattr(coro, 'cr_code') and not hasattr(coro, 'gi_code'): # Most likely a built-in type or a Cython coroutine. # Built-in types might not have __qualname__ or __name__. coro_name = getattr( coro, '__qualname__', getattr(coro, '__name__', type(coro).__name__)) coro_name = f'{coro_name}()' running = False try: running = coro.cr_running except AttributeError: try: running = coro.gi_running except AttributeError: pass if running: return f'{coro_name} running' else: return coro_name coro_name = None if isinstance(coro, CoroWrapper): func = coro.func coro_name = coro.__qualname__ if coro_name is not None: coro_name = f'{coro_name}()' else: func = coro if coro_name is None: coro_name = format_helpers._format_callback(func, (), {}) try: coro_code = coro.gi_code except AttributeError: coro_code = coro.cr_code try: coro_frame = coro.gi_frame except AttributeError: coro_frame = coro.cr_frame filename = coro_code.co_filename lineno = 0 if (isinstance(coro, CoroWrapper) and not inspect.isgeneratorfunction(coro.func) and coro.func is not None): source = format_helpers._get_function_source(coro.func) if source is not None: filename, lineno = source if coro_frame is None: coro_repr = f'{coro_name} done, defined at {filename}:{lineno}' else: coro_repr = f'{coro_name} running, defined at {filename}:{lineno}' elif coro_frame is not None: lineno = coro_frame.f_lineno coro_repr = f'{coro_name} running at {filename}:{lineno}' else: lineno = coro_code.co_firstlineno coro_repr = f'{coro_name} done, defined at {filename}:{lineno}' return coro_repr
# generator02 # 参考:http://python.jobbole.com/84527/ # def container(start, end): # while start < end: # print (start) # start += 1 from inspect import isgeneratorfunction def container(start, end): while start < end: yield start # 用于 创建 生成器generator start += 1 c = container(0, 59999999999999999999999999999) print(isgeneratorfunction(container)) print(type(c)) print(c) # 0,1,2,3,4 print(next(c)) # 01,2 # for i in c: # print(i) #StopIteration
def log(function=None, sensitives=None, customs=None, single_values=False): '''Log decorator to be used with :func:`simple_response`:: @simple_response @log def my_func(self, var1, var2): return "%s__%s" % (var1, var2) The above example will write two lines into the logfile for the module (given that the the UCR variable *umc/module/debug/level* is set to at least 3):: <date> MODULE ( INFO ) : my_func got: var1='value1', var2='value2' <date> MODULE ( INFO ) : my_func returned: 'value1__value2' The variable names are ordered by appearance and hold the values that are actually going to be passed to the function (i.e. after they were :func:`sanitize` 'd or set to their default value). You may specify the names of sensitive arguments that should not show up in log files and custom functions that can alter the representation of a certain variable's values (useful for non-standard datatypes like regular expressions - you may have used a :class:`~univention.management.console.modules.sanitizers.PatternSanitizer` ):: @sanitize(pattern=PatternSanitizer()) @simple_reponse @log(sensitives=['password'], customs={'pattern':lambda x: x.pattern}) def count_ucr(self, username, password, pattern): return self._ucr_count(username, password, pattern) This results in something like:: <date> MODULE ( INFO ) : count_ucr got: password='******', username='******', pattern='.*' <date> MODULE ( INFO ) : count_ucr returned: 650 The decorator also works with :func:`multi_response`:: @multi_response @log def multi_my_func(self, var1, var2): return "%s__%s" % (var1, var2) This results in something like:: <date> MODULE ( INFO ) : multi_my_func got: [var1='value1', var2='value2'], [var1='value3', var2='value4'] <date> MODULE ( INFO ) : multi_my_func returned: ['value1__value2', 'value3__value4'] ''' if function is None: return lambda f: log(f, sensitives, customs, single_values) if customs is None: customs = {} if sensitives is None: sensitives = [] for sensitive in sensitives: customs[sensitive] = lambda x: '********' def _log(names, args): if single_values: args = [args] return [ '%s=%r' % (name, customs.get(name, lambda x: x)(arg)) for name, arg in zip(names, args) ] # including self names, _ = arginspect(function) name = function.__name__ # multi_response yields i.e. is generator function if inspect.isgeneratorfunction(function): # remove self, iterator names = names[2:] def _response(self, iterator, *args): arg_reprs = [] for element in iterator: arg_repr = _log(names, element) if arg_repr: arg_reprs.append(arg_repr) if arg_reprs: MODULE.info('%s got: [%s]' % (name, '], ['.join(', '.join(arg_repr) for arg_repr in arg_reprs))) result = [] for res in function(self, iterator, *args): result.append(res) yield res MODULE.info('%s returned: %r' % (name, result)) else: # remove self names = names[1:] def _response(self, *args): arg_repr = _log(names, args) if arg_repr: MODULE.info('%s got: %s' % (name, ', '.join(arg_repr))) result = function(self, *args) MODULE.info('%s returned: %r' % (name, result)) return result copy_function_meta_data(function, _response, copy_arg_inspect=True) return _response
def is_generator(obj): """Return True if ``obj`` is a generator """ return inspect.isgeneratorfunction(obj) or inspect.isgenerator(obj)
def add_route(self, method, path, handler, *, name=None, expect_handler=None): if not path.startswith('/'): raise ValueError("path should be started with /") assert callable(handler), handler if asyncio.iscoroutinefunction(handler): pass elif inspect.isgeneratorfunction(handler): pass elif isinstance(handler, type) and issubclass(handler, AbstractView): pass else: handler = asyncio.coroutine(handler) method = upstr(method) if method not in self.METHODS: raise ValueError("{} is not allowed HTTP method".format(method)) if not ('{' in path or '}' in path or self.ROUTE_RE.search(path)): route = PlainRoute(method, handler, name, path, expect_handler=expect_handler) self.register_route(route) return route pattern = '' formatter = '' for part in self.ROUTE_RE.split(path): match = self.DYN.match(part) if match: pattern += '(?P<{}>{})'.format(match.group('var'), self.GOOD) formatter += '{' + match.group('var') + '}' continue match = self.DYN_WITH_RE.match(part) if match: pattern += '(?P<{var}>{re})'.format(**match.groupdict()) formatter += '{' + match.group('var') + '}' continue if '{' in part or '}' in part: raise ValueError("Invalid path '{}'['{}']".format(path, part)) formatter += part pattern += re.escape(part) try: compiled = re.compile('^' + pattern + '$') except re.error as exc: raise ValueError("Bad pattern '{}': {}".format(pattern, exc)) from None route = DynamicRoute(method, handler, name, compiled, formatter, expect_handler=expect_handler) self.register_route(route) return route
def _execute_and_send(self, cmd, args, match, msg, template_name=None): """Execute a bot command and send output back to the caller :param cmd: The command that was given to the bot (after being expanded) :param args: Arguments given along with cmd :param match: A re.MatchObject if command is coming from a regex-based command, else None :param msg: The message object :param template_name: The name of the jinja template which should be used to render the markdown output, if any """ private = cmd in self.bot_config.DIVERT_TO_PRIVATE threaded = cmd in self.bot_config.DIVERT_TO_THREAD commands = self.re_commands if match else self.commands try: with self._gbl: method = commands[cmd] # first check if we need to reattach a flow context flow, _ = self.flow_executor.check_inflight_flow_triggered( cmd, msg.frm) if flow: log.debug("Reattach context from flow %s to the message", flow._root.name) msg.ctx = flow.ctx elif method._err_command_flow_only: # check if it is a flow_only command but we are not in a flow. log.debug( "%s is tagged flow_only and we are not in a flow. Ignores the command.", cmd, ) return if inspect.isgeneratorfunction(method): replies = method(msg, match) if match else method(msg, args) for reply in replies: if reply: self.send_simple_reply( msg, self.process_template(template_name, reply), private, threaded, ) else: reply = method(msg, match) if match else method(msg, args) if reply: self.send_simple_reply( msg, self.process_template(template_name, reply), private, threaded, ) # The command is a success, check if this has not made a flow progressed self.flow_executor.trigger(cmd, msg.frm, msg.ctx) except CommandError as command_error: reason = command_error.reason if command_error.template: reason = self.process_template(command_error.template, reason) self.send_simple_reply(msg, reason, private, threaded) except Exception as e: tb = traceback.format_exc() log.exception( f'An error happened while processing a message ("{msg.body}"): {tb}"' ) self.send_simple_reply(msg, self.MSG_ERROR_OCCURRED + f":\n{e}", private, threaded)
def traversal_apply(self, func, filter_fn=lambda x: x is not None, order='pre', first='depth'): if order.lower() not in ['pre', 'post']: raise ValueError( 'Options for order are pre or post, {} given.'.format(order)) if first.lower() not in ['depth', 'breadth']: raise ValueError( 'Options for first are depth or breadth, {} given.'.format( first)) to_traversal = [ self, ] to_apply = [] while to_traversal: if first.lower() == 'depth': current = to_traversal.pop() else: current = to_traversal.pop(0) to_apply.append(current) if order.lower() == 'pre': current_apply = to_apply.pop() if inspect.isgeneratorfunction(func): # func: yield if filter_fn: yield from filter(filter_fn, func(current_apply)) else: yield from func(current_apply) else: # func: return retval = func(current_apply) if not filter_fn or filter_fn(retval): yield retval if isinstance(current, NamedTree): subs = [ current[name] for name in current ] # compatible to subclasses that override the iterator if (first.lower() == 'depth' and order.lower() == 'pre') or (first.lower() == 'breadth' and order.lower() == 'post'): subs = reversed(subs) to_traversal.extend(subs) if order.lower() == 'post': while to_apply: current_apply = to_apply.pop() if inspect.isgeneratorfunction(func): # func: yield if filter_fn: yield from filter(filter_fn, func(current_apply)) else: yield from func(current_apply) else: # func: return retval = func(current_apply) if not filter_fn or filter_fn(retval): yield retval
def _is_coroutine(obj): """Check to see if an object is really an asyncio coroutine.""" return asyncio.iscoroutinefunction(obj) or inspect.isgeneratorfunction(obj)
def isgeneratorfunction(object): # pylint: disable=redefined-builtin """TFDecorator-aware replacement for inspect.isgeneratorfunction.""" return _inspect.isgeneratorfunction( tf.__internal__.decorator.unwrap(object)[1])
def is_generator(func): genfunc = inspect.isgeneratorfunction(func) return genfunc and not iscoroutinefunction(func)
def _format_coroutine(coro): assert iscoroutine(coro) if not hasattr(coro, 'cr_code') and not hasattr(coro, 'gi_code'): # Most likely a Cython coroutine. coro_name = getattr(coro, '__qualname__', coro.__name__) coro_name = '{}()'.format(coro_name) running = False try: running = coro.cr_running except AttributeError: try: running = coro.gi_running except AttributeError: pass if running: return '{} running'.format(coro_name) else: return coro_name coro_name = None if isinstance(coro, CoroWrapper): func = coro.func coro_name = coro.__qualname__ if coro_name is not None: coro_name = '{}()'.format(coro_name) else: func = coro if coro_name is None: coro_name = events._format_callback(func, (), {}) try: coro_code = coro.gi_code except AttributeError: coro_code = coro.cr_code try: coro_frame = coro.gi_frame except AttributeError: coro_frame = coro.cr_frame filename = coro_code.co_filename lineno = 0 if (isinstance(coro, CoroWrapper) and not inspect.isgeneratorfunction(coro.func) and coro.func is not None): source = events._get_function_source(coro.func) if source is not None: filename, lineno = source if coro_frame is None: coro_repr = ('%s done, defined at %s:%s' % (coro_name, filename, lineno)) else: coro_repr = ('%s running, defined at %s:%s' % (coro_name, filename, lineno)) elif coro_frame is not None: lineno = coro_frame.f_lineno coro_repr = ('%s running at %s:%s' % (coro_name, filename, lineno)) else: lineno = coro_code.co_firstlineno coro_repr = ('%s done, defined at %s:%s' % (coro_name, filename, lineno)) return coro_repr