def index(session): all_paths = db.all_file_paths() recent_calls = (session.query(*(Call.basic_columns + Function.basic_columns)) .join(Function) .order_by(Call.start_time.desc())[:100]) files = OrderedDict() for row in recent_calls: if is_ipython_cell(row.file): continue files.setdefault( row.file, OrderedDict() ).setdefault( row.name, row ) for path in all_paths: files.setdefault( path, OrderedDict() ) short = partial(short_path, all_paths=all_paths) return render_template('index.html', short=short, files=files)
def all_file_paths(self): # type: () -> List[str] paths = [f[0] for f in self.Session().query(self.Function.file).distinct() if not is_ipython_cell(f[0])] paths.sort() if IPYTHON_FILE_PATH in paths: paths.remove(IPYTHON_FILE_PATH) paths.insert(0, IPYTHON_FILE_PATH) return paths
def trace_function(self, func): # type: (FunctionType) -> FunctionType """ Returns a version of the passed function with the AST modified to trigger the tracing hooks. """ if not isinstance(func, FunctionType): raise ValueError('You can only trace user-defined functions. ' 'The birdseye decorator must be applied first, ' 'at the bottom of the list.') try: if inspect.iscoroutinefunction(func) or inspect.isasyncgenfunction( func): raise ValueError('You cannot trace async functions') except AttributeError: pass if is_lambda(func): raise ValueError('You cannot trace lambdas') filename = inspect.getsourcefile(func) # type: str if is_ipython_cell(filename): # noinspection PyPackageRequirements from IPython import get_ipython import linecache flags = get_ipython().compile.flags source = ''.join(linecache.cache[filename][2]) else: source = read_source_file(filename) flags = 0 # We compile the entire file instead of just the function source # because it can contain context which affects the function code, # e.g. enclosing functions and classes or __future__ imports traced_file = self.compile(source, filename, flags) if func.__dict__: raise ValueError('The birdseye decorator must be applied first, ' 'at the bottom of the list.') # Then we have to recursively search through the newly compiled # code to find the code we actually want corresponding to this function code_options = [] # type: List[CodeType] def find_code(root_code): # type: (CodeType) -> None for const in root_code.co_consts: # type: CodeType if not inspect.iscode(const): continue matches = (const.co_firstlineno == func.__code__.co_firstlineno and const.co_name == func.__code__.co_name) if matches: code_options.append(const) find_code(const) find_code(traced_file.code) if len(code_options) > 1: # Currently lambdas aren't allowed anyway, but should be in the future assert is_lambda(func) raise ValueError( "Failed to trace lambda. Convert the function to a def.") new_func_code = code_options[0] # type: CodeType # Give the new function access to the hooks # We have to use the original __globals__ and not a copy # because it's the actual module namespace that may get updated by other code func.__globals__.update(self._trace_methods_dict(traced_file)) # http://stackoverflow.com/a/13503277/2482744 # noinspection PyArgumentList new_func = FunctionType(new_func_code, func.__globals__, func.__name__, func.__defaults__, func.__closure__) update_wrapper(new_func, func) # type: FunctionType if PY3: new_func.__kwdefaults__ = getattr(func, '__kwdefaults__', None) new_func.traced_file = traced_file return new_func