Beispiel #1
0
    def test_strip_indent(self, find_indent_mock):
        find_indent_mock.return_value = 4

        indented_source = """
    def foo():
        x = 3

        y = 4
        # Comment here
        if x == 3:
            y = 5
        return x + y
"""
        stripped_source = """
def foo():
    x = 3

    y = 4
    # Comment here
    if x == 3:
        y = 5
    return x + y
"""

        self.assertEqual(strip_indent(indented_source), stripped_source,
                         "Incorrectly stripped indentation.")
Beispiel #2
0
    def _record(f):
        """Transforms `f` such that after every line record_state is called.

        *** HERE BE DRAGONS ***
        """
        global num_fns_recorded

        # Make sure this is not a recursive decorator application.
        global _blocked
        if _blocked:
            return f

        # We only support recording one fn's executions at the moment.
        if num_fns_recorded:
            raise ValueError(
                'Cannot `record` more than one function at a time.')
        num_fns_recorded += 1

        source = inspect.getsource(f)
        parsed = ast.parse(strip_indent(source))
        original_body = list(parsed.body[0].body)

        # Update body
        parsed.body[0].body = _fill_body_with_record(original_body)

        # Compile and inject modified function back into its env.
        new_f_compiled = compile(parsed, '<string>', 'exec')
        env = sys.modules[f.__module__].__dict__
        # We also need to inject our stuff in there.
        env[RECORD_FN_NAME] = globals()[RECORD_FN_NAME]

        _blocked = True
        exec new_f_compiled in env
        _blocked = False

        # Keep a reference to the (original) mangled function, because our decorator
        # will end up replacing it with `wrapped`. Then, whenever `wrapped` ends up
        # calling the original function, it would end up calling itself, leading
        # to an infinite recursion. Thus, we keep the fn we want to call under
        # a separate key which `wrapped` can call without a problem.
        # We are doing this instead of simply changing the recorded fn's name because
        # we have to support recursive calls (which would lead to NameError if we changed
        # the fn's name).
        env[MANGLED_FN_NAME] = env[f.__name__]

        init_recorded_state()

        file, path = _get_dump_file()
        logger.info(
            "Will record execution of %s in %s . "
            "Use `view_trace %s` to view it.", f.__name__, path, path)

        # Wrap in our own function such that we can dump the recorded state at the end.
        @wraps(f)
        def wrapped(*args, **kwargs):
            # Write source to file the first time we are called.
            global first_dump_call
            if first_dump_call:
                dump_fn_source(file, source)
                first_dump_call = False

            global num_recorded_executions
            # Are we still recording?
            if num_recorded_executions < num_executions:
                # Clear state for new run.
                init_recorded_state()

                ret = env[MANGLED_FN_NAME](*args, **kwargs)

                dump_recorded_state(file)
                num_recorded_executions += 1

            # If not, just call the original function.
            else:
                ret = f(*args, **kwargs)

            return ret

        return wrapped
    def _record(f):
        """Transforms `f` such that after every line record_state is called.

        *** HERE BE DRAGONS ***
        """
        global num_fns_recorded

        # Make sure this is not a recursive decorator application.
        global _blocked
        if _blocked:
            return f

        # We only support recording one fn's executions at the moment.
        if num_fns_recorded:
            raise ValueError('Cannot `record` more than one function at a time.')
        num_fns_recorded += 1

        source = inspect.getsource(f)
        parsed = ast.parse(strip_indent(source))
        original_body = list(parsed.body[0].body)

        # Update body
        parsed.body[0].body = _fill_body_with_record(original_body)

        # Compile and inject modified function back into its env.
        new_f_compiled = compile(parsed, '<string>', 'exec')
        env = sys.modules[f.__module__].__dict__
        # We also need to inject our stuff in there.
        env[RECORD_FN_NAME] = globals()[RECORD_FN_NAME]

        _blocked = True
        exec new_f_compiled in env
        _blocked = False

        # Keep a reference to the (original) mangled function, because our decorator
        # will end up replacing it with `wrapped`. Then, whenever `wrapped` ends up
        # calling the original function, it would end up calling itself, leading
        # to an infinite recursion. Thus, we keep the fn we want to call under
        # a separate key which `wrapped` can call without a problem.
        # We are doing this instead of simply changing the recorded fn's name because
        # we have to support recursive calls (which would lead to NameError if we changed
        # the fn's name).
        env[MANGLED_FN_NAME] = env[f.__name__]

        init_recorded_state()

        file, path = _get_dump_file()
        logger.info("Will record execution of %s in %s . "
                    "Use `view_trace %s` to view it.",
                    f.__name__, path, path)

        # Wrap in our own function such that we can dump the recorded state at the end.
        @wraps(f)
        def wrapped(*args, **kwargs):
            # Write source to file the first time we are called.
            global first_dump_call
            if first_dump_call:
                dump_fn_source(file, source)
                first_dump_call = False


            global num_recorded_executions
            # Are we still recording?
            if num_recorded_executions < num_executions:
                # Clear state for new run.
                init_recorded_state()

                ret = env[MANGLED_FN_NAME](*args, **kwargs)

                dump_recorded_state(file)
                num_recorded_executions += 1

            # If not, just call the original function.
            else:
                ret = f(*args, **kwargs)

            return ret

        return wrapped