Exemple #1
0
 def _db_func(self, data, filename, html_body, name, start_lineno):
     """
     Retrieve the Function object from the database if one exists, or create one.
     """
     function_hash = hashlib.sha256((filename + name + html_body + data + str(start_lineno)
                                     ).encode('utf8')).hexdigest()
     db_func = one_or_none(session.query(Function).filter_by(hash=function_hash))  # type: Optional[Function]
     if not db_func:
         db_func = Function(file=filename,
                            name=name,
                            html_body=html_body,
                            lineno=start_lineno,
                            data=data,
                            hash=function_hash)
         session.add(db_func)
         session.commit()
     return db_func
Exemple #2
0
    def __call__(self, func):
        if inspect.isclass(func):
            cls = func
            for name, meth in iteritems(cls.__dict__):
                if inspect.ismethod(meth) or inspect.isfunction(meth):
                    setattr(cls, name, self.__call__(meth))
            return cls

        new_func = super(BirdsEye, self).__call__(func)
        code_info = self._code_infos.get(new_func.__code__)
        if code_info:
            return new_func
        lines, start_lineno = inspect.getsourcelines(func)
        end_lineno = start_lineno + len(lines)
        name = safe_qualname(func)
        filename = os.path.abspath(inspect.getsourcefile(func))

        traced_file = new_func.traced_file
        traced_file.root._depth = 0
        for node in ast.walk(traced_file.root):
            for child in ast.iter_child_nodes(node):
                child._depth = node._depth + 1

        positions = []
        node_loops = {}
        for node in traced_file.nodes:
            if isinstance(node, ast.expr):
                node_type = 'expr'
                if not node._is_interesting_expression:
                    continue
            elif (isinstance(node, (ast.While, ast.For, ast.comprehension))
                  and not isinstance(node.parent, ast.GeneratorExp)):
                node_type = 'loop'
            elif isinstance(node, ast.stmt):
                node_type = 'stmt'
            else:
                continue
            assert isinstance(node, ast.AST)

            # In particular FormattedValue is missing this
            if not hasattr(node, 'first_token'):
                continue

            if not start_lineno <= node.first_token.start[0] <= end_lineno:
                continue

            start, end = traced_file.tokens.get_text_range(node)
            if start == end == 0:
                continue
            positions.append((start, 1, node._depth,
                              '<span data-index="%s" data-type="%s">' %
                              (node._tree_index, node_type)))
            positions.append((end, 0, node._depth, '</span>'))
            if node._loops:
                node_loops[node._tree_index] = [
                    n._tree_index for n in node._loops
                ]

        comprehensions = group_by_key_func([
            comp for comp in traced_file.nodes
            if isinstance(comp, ast.comprehension)
        ], lambda c: c.first_token.line)

        def get_start(n):
            return traced_file.tokens.get_text_range(n)[0]

        for comp_list in comprehensions.values():
            prev_start = None
            for comp in sorted(comp_list,
                               key=lambda c: c.first_token.startpos):
                if comp is comp.parent.generators[0]:
                    start = get_start(comp.parent)
                    if prev_start is not None and start < prev_start:
                        start = get_start(comp)
                else:
                    start = get_start(comp)
                if prev_start is not None:
                    positions.append((start, 1, 0, '\n '))
                    end_lineno += 1
                prev_start = start

        positions.append((len(traced_file.source), None, None, ''))
        positions.sort()

        html_body = []
        start = 0
        for pos, _, _, part in positions:
            html_body.append(html.escape(traced_file.source[start:pos]))
            html_body.append(part)
            start = pos
        html_body = ''.join(html_body)
        html_body = '\n'.join(
            html_body.split('\n')[start_lineno - 1:end_lineno - 1])

        db_args = dict(file=filename,
                       name=name,
                       html_body=html_body,
                       lineno=start_lineno,
                       data=json.dumps(
                           dict(node_loops=node_loops, ),
                           sort_keys=True,
                       ))

        db_func = one_or_none(session.query(Function).filter_by(**db_args))
        if not db_func:
            db_func = Function(**db_args)
            session.add(db_func)
            session.commit()
        self._code_infos[new_func.__code__] = CodeInfo(db_func, traced_file)

        return new_func