def create_call(self, call_type, definition, callable, args, code, frame): sargs = self.serialize_call_arguments(args) if is_generator_code(code): generator = get_generator_from_frame(frame) # Each generator invocation is related to some generator object, # so we have to create one if it wasn't captured yet. def create_generator_object(_): gobject = GeneratorObject(generator, definition, sargs, callable) save_generator_inside(gobject, generator) return gobject gobject = self._retrieve_or_capture(generator, create_generator_object) # It may have been captured, but not necessarily invoked yet, so # we activate it if that's the case. if not gobject.is_activated(): gobject.activate(definition, sargs, callable) save_generator_inside(gobject, generator) # In case of generators the call is really an invocation (resume) of # a specific generator object. Input arguments were already saved # in the GeneratorObject, and there's no need for duplicating them. call_type = GeneratorObjectInvocation callable = gobject sargs = {} call = call_type(definition, sargs) self.captured_calls.append(call) callable.add_call(call) return call
def is_generator_definition(definition): """Return True if given piece of code is a generator definition. >>> is_generator_definition("def f():\\n return 1\\n") False >>> is_generator_definition("def g():\\n yield 2\\n") True >>> is_generator_definition(" def indented_gen():\\n yield 3\\n") True >>> is_generator_definition("\\n def indented_gen():\\n yield 3\\n") True """ try: return is_generator_code(function_code_from_definition(definition)) except SyntaxError: # This most likely means given code used "return" with argument # inside generator. return False