Exemple #1
0
def getblocks_from_history(object, lstrip=False):# gettype=False):
    """extract code blocks from a code object using stored history"""
    import readline, inspect, types
    lbuf = readline.get_current_history_length()
    code = [readline.get_history_item(i)+'\n' for i in range(1,lbuf)]
    lnum = 0
    codeblocks = []
   #objtypes = []
    while lnum < len(code):#-1:
       if code[lnum].lstrip().startswith('def '):
           block = inspect.getblock(code[lnum:])
           lnum += len(block)
           if block[0].lstrip().startswith('def %s(' % object.func_name):
               if lstrip: block[0] = block[0].lstrip()
               codeblocks.append(block)
   #           obtypes.append(types.FunctionType)
       elif 'lambda ' in code[lnum]:
           block = inspect.getblock(code[lnum:])
           lnum += len(block)
           lhs,rhs = block[0].split('lambda ',1)[-1].split(":", 1) #FIXME: bad
           try: #FIXME: unsafe
               _ = eval("lambda %s : %s" % (lhs, rhs), globals(), locals())
           except: pass
           if _.func_code.co_code == object.func_code.co_code:
               if lstrip: block[0] = block[0].lstrip()
               codeblocks.append(block)
   #           obtypes.append('<lambda>')
       else:
           lnum +=1
   #if gettype: return codeblocks, objtypes 
    return codeblocks #XXX: danger... gets methods and closures w/o containers
Exemple #2
0
def getblocks(object, lstrip=False):# gettype=False):
    """extract code blocks from a code object using stored history"""
    import readline, inspect #, types
    lbuf = readline.get_current_history_length()
    code = [readline.get_history_item(i)+'\n' for i in range(1,lbuf)]
    lnum = 0
    codeblocks = []
   #objtypes = []
    try:
        if PYTHON3:
            fname = object.__name__
            ocode = object.__code__
        else:
            fname = object.func_name
            ocode = object.func_code
        cname = ''
    except AttributeError:
        fname = ''
        ocode = lambda :'__this_is_a_big_dummy_object__'
        ocode.co_code = '__this_is_a_big_dummy_co_code__'
       #try: inspect.getmro(object) #XXX: ensure that it's a class
        if hasattr(object, '__name__'): cname = object.__name__ # class
        else: cname = object.__class__.__name__ # instance
    while lnum < len(code):#-1:
        if fname and code[lnum].lstrip().startswith('def '):
            # functions and methods
            block = inspect.getblock(code[lnum:])
            lnum += len(block)
            if block[0].lstrip().startswith('def %s(' % fname):
                if lstrip: block[0] = block[0].lstrip()
                codeblocks.append(block)
   #            obtypes.append(types.FunctionType)
        elif cname and code[lnum].lstrip().startswith('class '):
            # classes and instances
            block = inspect.getblock(code[lnum:])
            lnum += len(block)
            _cname = ('class %s(' % cname, 'class %s:' % cname)
            if block[0].lstrip().startswith(_cname):
                if lstrip: block[0] = block[0].lstrip()
                codeblocks.append(block)
        elif fname and 'lambda ' in code[lnum]:
            # lambdas
            block = inspect.getblock(code[lnum:])
            lnum += len(block)
            lhs,rhs = block[0].split('lambda ',1)[-1].split(":", 1) #FIXME: bad
            try: #FIXME: unsafe
                _ = eval("lambda %s : %s" % (lhs, rhs), globals(), locals())
            except: _ = lambda : "__this_is_a_big_dummy_function__"
            if PYTHON3: _ = _.__code__
            else: _ = _.func_code
            if _.co_code == ocode.co_code:
                if lstrip: block[0] = block[0].lstrip()
                codeblocks.append(block)
   #            obtypes.append('<lambda>')
        #XXX: would be nice to grab constructor for instance, but yikes.
        else:
            lnum +=1
   #if gettype: return codeblocks, objtypes 
    return codeblocks #XXX: danger... gets methods and closures w/o containers
    def __prepare__(meta, name, bases):
        bare_cls = meta("<Bare>", bases, SettingsDict(options=None, bare_cls=None))

        frame = sys._getframe(1)
        filename = inspect.getsourcefile(frame)
        with tokenize.open(filename) as file:
            lines = file.readlines()[frame.f_lineno - 1 :]
        source = "".join(inspect.getblock(lines))
        source = textwrap.dedent(source.expandtabs(tabsize=8))

        cls_node = ast.parse(source).body[0]
        for node in reversed(list(ast.iter_child_nodes(cls_node))):
            if isinstance(node, ast.ClassDef) and node.name == "Meta":
                cf_mask = sum(
                    getattr(__future__, feature).compiler_flag
                    for feature in __future__.all_feature_names
                )
                code = compile(
                    ast.Module(body=[node], type_ignores=[]),
                    filename="<meta>",
                    mode="exec",
                    flags=frame.f_code.co_flags & cf_mask,
                    dont_inherit=True,
                )
                globals = frame.f_globals
                locals = {}
                exec(code, globals, locals)
                meta = locals["Meta"]
                break
        else:
            meta = getattr(bare_cls, "Meta", None)
        options = Options(meta)
        bare_cls._options = options
        return SettingsDict(options=options, bare_cls=bare_cls)
Exemple #4
0
def getsourcelines(object):
    """Return a list of source lines and starting line number for an object.

    Parameters
    ----------
    object : a python object 
       The argument may be a module, class, method, function, traceback, frame,
       or code object.  The source code is returned as a string with the lines
       corresponding to the object and the line number indicates where in the
       original source file the first line of code was found.  An IOError is
       raised if the source code cannot be retrieved."""

    lines, lnum = inspect.findsource(object)
    if inspect.ismodule(object):
        lnum = 0
        ss = ''
        for x in lines:
            ss += x
    else:
        lines = inspect.getblock(lines[lnum:])
        lnum = lnum + 1
        ss = ''
        for x in lines:
            ss += x

    return ss, 0
    def get_annotated_lines(self):
        """Helper function that returns lines with extra information."""
        lines = [Line(idx + 1, x) for idx, x in enumerate(self.sourcelines)]

        # find function definition and mark lines
        if hasattr(self.code, 'co_firstlineno'):
            lineno = self.code.co_firstlineno - 1
            while lineno > 0:
                if _funcdef_re.match(lines[lineno].code):
                    break
                lineno -= 1
            try:
                offset = len(inspect.getblock([x.code + '\n' for x
                                               in lines[lineno:]]))
            except TokenError:
                offset = 0
            for line in lines[lineno:lineno + offset]:
                line.in_frame = True

        # mark current line
        try:
            lines[self.lineno - 1].current = True
        except IndexError:
            pass

        return lines
Exemple #6
0
    def get_annotated_lines(self):
        """Helper function that returns lines with extra information."""
        lines = [Line(idx + 1, x) for idx, x in enumerate(self.sourcelines)]

        # find function definition and mark lines
        if hasattr(self.code, "co_firstlineno"):
            lineno = self.code.co_firstlineno - 1
            while lineno > 0:
                if _funcdef_re.match(lines[lineno].code):
                    break
                lineno -= 1
            try:
                offset = len(
                    inspect.getblock([x.code + "\n" for x in lines[lineno:]]))
            except TokenError:
                offset = 0
            for line in lines[lineno:lineno + offset]:
                line.in_frame = True

        # mark current line
        try:
            lines[self.lineno - 1].current = True
        except IndexError:
            pass

        return lines
Exemple #7
0
def show_results(prof, stream=None, precision=3):
    if stream is None:
        stream = sys.stdout
    template = '{0:>6} {1:>12} {2:>12}   {3:<}'

    for code in prof.code_map:
        lines = prof.code_map[code]
        if not lines:
            # .. measurements are empty ..
            continue
        filename = code.co_filename
        if filename.endswith((".pyc", ".pyo")):
            filename = filename[:-1]
        stream.write('Filename: ' + filename + '\n\n')
        if not os.path.exists(filename):
            stream.write('ERROR: Could not find file ' + filename + '\n')
            if filename.startswith("ipython-input") or filename.startswith("<ipython-input"):
                print(
                    "NOTE: %mprun can only be used on functions defined in "
                    "physical files, and not in the IPython environment."
                )
            continue
        all_lines = linecache.getlines(filename)
        sub_lines = inspect.getblock(all_lines[code.co_firstlineno - 1 :])
        linenos = range(code.co_firstlineno, code.co_firstlineno + len(sub_lines))
        lines_normalized = {}

        header = template.format('Line #', 'Mem usage', 'Increment', 'Line Contents')
        stream.write(header + '\n')
        stream.write('=' * len(header) + '\n')
        # move everything one frame up
        keys = sorted(lines.keys())

        k_old = keys[0] - 1
        lines_normalized[keys[0] - 1] = lines[keys[0]]
        for i in range(1, len(lines_normalized[keys[0] - 1])):
            lines_normalized[keys[0] - 1][i] = -1.0
        k = keys.pop(0)
        while keys:
            lines_normalized[k] = lines[keys[0]]
            for i in range(len(lines_normalized[k_old]), len(lines_normalized[k])):
                lines_normalized[k][i] = -1.0
            k_old = k
            k = keys.pop(0)

        first_line = sorted(lines_normalized.keys())[0]
        mem_old = max(lines_normalized[first_line])
        precision = int(precision)
        template_mem = '{{0:{0}.{1}'.format(precision + 6, precision) + 'f} MB'
        for i, l in enumerate(linenos):
            mem = ''
            inc = ''
            if l in lines_normalized:
                mem = max(lines_normalized[l])
                inc = mem - mem_old
                mem_old = mem
                mem = template_mem.format(mem)
                inc = template_mem.format(inc)
            stream.write(template.format(l, mem, inc, sub_lines[i]))
        stream.write('\n\n')
    def load_data(self, profdatafile):
        """Load line profiler data saved by kernprof.py module"""
        # lstats has the following layout :
        # lstats.timings =
        #     {(filename1, line_no1, function_name1):
        #         [(line_no1, hits1, total_time1),
        #          (line_no2, hits2, total_time2)],
        #      (filename2, line_no2, function_name2):
        #         [(line_no1, hits1, total_time1),
        #          (line_no2, hits2, total_time2),
        #          (line_no3, hits3, total_time3)]}
        # lstats.unit = time_factor
        with open(profdatafile, 'rb') as fid:
            lstats = cPickle.load(fid)

        # First pass to group by filename
        self.stats = dict()
        linecache.checkcache()
        for func_info, stats in lstats.timings.iteritems():
            # func_info is a tuple containing (filename, line, function anme)
            filename, start_line_no = func_info[:2]
            filename = filename.decode('utf8')

            # Read code
            start_line_no -= 1  # include the @profile decorator
            all_lines = linecache.getlines(filename)
            block_lines = inspect.getblock(all_lines[start_line_no:])

            # Loop on each line of code
            func_stats = []
            func_total_time = 0.0
            next_stat_line = 0
            for line_no, code_line in enumerate(block_lines):
                line_no += start_line_no + 1  # Lines start at 1
                code_line = code_line.rstrip('\n').decode('utf8')
                if (next_stat_line >= len(stats)
                        or line_no != stats[next_stat_line][0]):
                    # Line didn't run
                    hits, line_total_time, time_per_hit = None, None, None
                else:
                    # Compute line times
                    hits, line_total_time = stats[next_stat_line][1:]
                    line_total_time *= lstats.unit
                    time_per_hit = line_total_time / hits
                    func_total_time += line_total_time
                    next_stat_line += 1
                func_stats.append(
                    [line_no, code_line, line_total_time, time_per_hit,
                     hits])

            # Compute percent time
            for line in func_stats:
                line_total_time = line[2]
                if line_total_time is None:
                    line.append(None)
                else:
                    line.append(line_total_time / func_total_time)

            # Fill dict
            self.stats[func_info] = [func_stats, func_total_time]
Exemple #9
0
def _extract_source(lines, lineno):
    r"""
    Given a list of lines or a multiline string and a starting lineno,
    _extract_source returns [source_lines].  [source_lines] is the smallest
    indentation block starting at lineno.

    INPUT:

    - ``lines`` - string or list of strings
    - ``lineno`` - positive integer

    EXAMPLES::

        sage: from sagenb.misc.sageinspect import _extract_source
        sage: s2 = "#hello\n\n  class f():\n    pass\n\n#goodbye"
        sage: _extract_source(s2, 3)
        ['  class f():\n', '    pass\n']
    """
    if lineno < 1:
        raise ValueError, "Line numbering starts at 1! (tried to extract line %s)" % lineno
    lineno -= 1
    
    if isinstance(lines, str):
        lines = lines.splitlines(True) # true keeps the '\n'
    if len(lines) > 0:
        # Fixes an issue with getblock
        lines[-1] += '\n'

    return inspect.getblock(lines[lineno:])
Exemple #10
0
def getsourcelines(obj):
    (lines, lineno) = inspect.findsource(obj)
    if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
        return (lines, 1)
    if inspect.ismodule(obj):
        return (lines, 1)
    return (inspect.getblock(lines[lineno:]), lineno + 1)
Exemple #11
0
    def render_source(self):
        """Render the sourcecode."""
        lines = [Line(idx + 1, x) for idx, x in enumerate(self.sourcelines)]

        # find function definition and mark lines
        if hasattr(self.code, 'co_firstlineno'):
            lineno = self.code.co_firstlineno - 1
            while lineno > 0:
                if _funcdef_re.match(lines[lineno].code):
                    break
                lineno -= 1
            try:
                offset = len(inspect.getblock([x.code + '\n' for x
                                               in lines[lineno:]]))
            except TokenError:
                offset = 0
            for line in lines[lineno:lineno + offset]:
                line.in_frame = True

        # mark current line
        try:
            lines[self.lineno - 1].current = True
        except IndexError:
            pass

        return render_template('source.html', frame=self, lines=lines)
def show_results(prof, stream=None):

    if stream is None:
        stream = sys.stdout
    template = '%6s %12s   %-s'
    header = template % ('Line #', 'Mem usage', 'Line Contents')
    stream.write(header + '\n')
    stream.write('=' * len(header) + '\n')

    for code in prof.code_map:
        lines = prof.code_map[code]
        filename = code.co_filename
        if (filename.endswith(".pyc") or
            filename.endswith(".pyo")):
            filename = filename[:-1]
        all_lines = linecache.getlines(filename)
        sub_lines = inspect.getblock(all_lines[code.co_firstlineno-1:])
        linenos = range(code.co_firstlineno, code.co_firstlineno + len(sub_lines))
        lines_normalized = {}

        # move everything one frame up
        keys = lines.keys()
        keys.sort()
        lines_normalized[code.co_firstlineno+1] = lines[keys[0]]
        while len(keys) > 1:
            v = keys.pop(0)
            lines_normalized[v] = lines[keys[0]]

        for l in linenos:
            mem = ''
            if lines_normalized.has_key(l):
                mem = '%5.2f MB' % max(lines_normalized.get(l))
            line = linecache.getline(filename, l)
            stream.write(template % (l, mem, line))
def getsourcelines(obj):
    (lines, lineno) = inspect.findsource(obj)
    if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
        return (lines, 1)
    if inspect.ismodule(obj):
        return (lines, 1)
    return (inspect.getblock(lines[lineno:]), lineno + 1)
Exemple #14
0
def getsourcelines(object):
    """Return a list of source lines and starting line number for an object.

    Parameters
    ----------
    object : a python object 
       The argument may be a module, class, method, function, traceback, frame,
       or code object.  The source code is returned as a string with the lines
       corresponding to the object and the line number indicates where in the
       original source file the first line of code was found.  An IOError is
       raised if the source code cannot be retrieved."""
    
    lines, lnum = inspect.findsource(object)
    if inspect.ismodule(object):
        lnum = 0
        ss = ''
        for x in lines:
            ss += x
    else:
        lines = inspect.getblock(lines[lnum:])
        lnum = lnum + 1
        ss = ''
        for x in lines:
            ss += x

    return ss, 0   
Exemple #15
0
def get_func_real_firstlineno(func):
    start_lineno = 0
    lines = linecache.getlines(func.__code__.co_filename)
    cls = _findclass(func)
    if cls:
        lines, lnum = findsource(cls)
        lines = getblock(lines[lnum:])
        start_lineno = lnum

    #  referenced from inspect _findclass
    pat = re.compile(r'^(\s*)def\s*' + func.__name__ + r'\b')
    candidates = []
    for i in range(len(lines)):
        match = pat.match(lines[i])
        if match:
            # if it's at toplevel, it's already the best one
            if lines[i][0] == 'd':
                return (i + start_lineno)
            # else add whitespace to candidate list
            candidates.append((match.group(1), i))
    if candidates:
        # this will sort by whitespace, and by line number,
        # less whitespace first
        candidates.sort()
        return start_lineno + candidates[0][1]
    else:
        raise OSError('could not find function definition')
Exemple #16
0
    def render_source(self):
        """Render the sourcecode."""
        lines = [Line(idx + 1, x) for idx, x in enumerate(self.sourcelines)]

        # find function definition and mark lines
        if hasattr(self.code, 'co_firstlineno'):
            lineno = self.code.co_firstlineno - 1
            while lineno > 0:
                if _funcdef_re.match(lines[lineno].code):
                    break
                lineno -= 1
            try:
                offset = len(
                    inspect.getblock([x.code + '\n' for x in lines[lineno:]]))
            except TokenError:
                offset = 0
            for line in lines[lineno:lineno + offset]:
                line.in_frame = True

        # mark current line
        try:
            lines[self.lineno - 1].current = True
        except IndexError:
            pass

        return render_template('source.html', frame=self, lines=lines)
Exemple #17
0
def _get_source(function):
    """
    Custom parser because built-in of Python fails sometimes.

    This function parses student-solution sourcecode.
    """

    name = function.__name__
    file = getsourcefile(function)

    # Get lines
    linecache.checkcache(file)
    module = getmodule(function, file)
    lines = linecache.getlines(file, module.__dict__)

    # Parse lines
    pat = re.compile("(def {}\()".format(name))  # Begin of function pattern.

    for lnum, line in enumerate(lines):
        if pat.match(line):
            break

    src = getblock(lines[lnum:])
    src = "".join(src)

    return src
Exemple #18
0
    def load_data(self, profdatafile):
        """Load line profiler data saved by kernprof module"""
        # lstats has the following layout :
        # lstats.timings =
        #     {(filename1, line_no1, function_name1):
        #         [(line_no1, hits1, total_time1),
        #          (line_no2, hits2, total_time2)],
        #      (filename2, line_no2, function_name2):
        #         [(line_no1, hits1, total_time1),
        #          (line_no2, hits2, total_time2),
        #          (line_no3, hits3, total_time3)]}
        # lstats.unit = time_factor
        with open(profdatafile, 'rb') as fid:
            lstats = pickle.load(fid)

        # First pass to group by filename
        self.stats = dict()
        linecache.checkcache()
        for func_info, stats in lstats.timings.items():
            # func_info is a tuple containing (filename, line, function anme)
            filename, start_line_no = func_info[:2]

            # Read code
            start_line_no -= 1  # include the @profile decorator
            all_lines = linecache.getlines(filename)
            block_lines = inspect.getblock(all_lines[start_line_no:])

            # Loop on each line of code
            func_stats = []
            func_total_time = 0.0
            next_stat_line = 0
            for line_no, code_line in enumerate(block_lines):
                line_no += start_line_no + 1  # Lines start at 1
                code_line = code_line.rstrip('\n')
                if (next_stat_line >= len(stats)
                        or line_no != stats[next_stat_line][0]):
                    # Line didn't run
                    hits, line_total_time, time_per_hit = None, None, None
                else:
                    # Compute line times
                    hits, line_total_time = stats[next_stat_line][1:]
                    line_total_time *= lstats.unit
                    time_per_hit = line_total_time / hits
                    func_total_time += line_total_time
                    next_stat_line += 1
                func_stats.append(
                    [line_no, code_line, line_total_time, time_per_hit,
                     hits])

            # Compute percent time
            for line in func_stats:
                line_total_time = line[2]
                if line_total_time is None:
                    line.append(None)
                else:
                    line.append(line_total_time / func_total_time)

            # Fill dict
            self.stats[func_info] = [func_stats, func_total_time]
def getsourcefallback(cls):
    """ Fallback for getting the source of interactively defined classes (typically in ipython)

    This is basically just a patched version of the inspect module, in which
    we get the code by calling inspect.findsource on an *instancemethod* of
    a class for which inspect.findsource fails.
    """
    for attr in cls.__dict__:
        if inspect.ismethod(getattr(cls, attr)):
            imethod = getattr(cls, attr)
            break
    else:
        raise AttributeError(
            "Cannot get this class' source; it does not appear to have any methods")

    ### This part is derived from inspect.findsource ###
    module = inspect.getmodule(cls)
    file = inspect.getfile(imethod)
    lines = linecache.getlines(file, module.__dict__)
    name = cls.__name__
    pat = re.compile(r'^(\s*)class\s*'+name+r'\b')

    # AMVMOD: find the encoding (necessary for python 2 only)
    #if PY2:
    #    with open(file, 'rb') as infile:
    #        encoding = detect_encoding(infile.readline)[0]

    # make some effort to find the best matching class definition:
    # use the one with the least indentation, which is the one
    # that's most probably not inside a function definition.
    candidates = []
    toplevel = False
    for i in range(len(lines)):
        match = pat.match(lines[i])
        if match:
            # if it's at toplevel, it's already the best one
            if lines[i][0] == 'c':
                flines, flnum = lines, i
                toplevel = True
                break
            # else add whitespace to candidate list
            candidates.append((match.group(1), i))
    if candidates and not toplevel:
        # this will sort by whitespace, and by line number,
        # less whitespace first
        candidates.sort()
        flines, flnum = lines, candidates[0][1]
    elif not candidates and not toplevel:
        raise IOError('could not find class definition')
    ### end modified inspect.findsource ###

    # this is what inspect.getsourcelines does
    glines = inspect.getblock(flines[flnum:])

    # And this is what inspect.getsource does
    if False: #if PY2:
        return ("".join(glines)).decode(encoding)
    else:
        return "".join(glines)
def show_func(filename, start_lineno, func_name, timings, unit, stream=None, stripzeros=False):
    """ Show results for a single function.
    """
    if stream is None:
        stream = sys.stdout

    template = '%6s %9s %12s %8s %8s  %-s'
    d = {}
    total_time = 0.0
    linenos = []
    for lineno, nhits, time in timings:
        total_time += time
        linenos.append(lineno)

    if stripzeros and total_time == 0:
        return

    stream.write("Total time: %g s\n" % (total_time * unit))
    if os.path.exists(filename) or filename.startswith("<ipython-input-"):
        stream.write("File: %s\n" % filename)
        stream.write("Function: %s at line %s\n" % (func_name, start_lineno))
        if os.path.exists(filename):
            # Clear the cache to ensure that we get up-to-date results.
            linecache.clearcache()
        all_lines = linecache.getlines(filename)
        sublines = inspect.getblock(all_lines[start_lineno-1:])
    else:
        stream.write("\n")
        stream.write("Could not find file %s\n" % filename)
        stream.write("Are you sure you are running this program from the same directory\n")
        stream.write("that you ran the profiler from?\n")
        stream.write("Continuing without the function's contents.\n")
        # Fake empty lines so we can see the timings, if not the code.
        if linenos:
            nlines = max(linenos) - min(min(linenos), start_lineno) + 1
        else:
            nlines = 1
        sublines = [''] * nlines

    for lineno, nhits, time in timings:
        d[lineno] = (nhits, time, '%5.1f' % (float(time) / nhits if nhits else 0),
            '%5.1f' % (100*time / total_time if total_time else 0))
    linenos = range(start_lineno, start_lineno + len(sublines))
    empty = ('', '', '', '')
    header = template % ('Line #', 'Hits', 'Time', 'Per Hit', '% Time',
        'Line Contents')
    stream.write("\n")
    stream.write(header)
    stream.write("\n")
    stream.write('=' * len(header))
    stream.write("\n")
    if total_time > 0:
        for lineno, line in zip(linenos, sublines):
            nhits, time, per_hit, percent = d.get(lineno, empty)
            txt = template % (lineno, nhits, time, per_hit, percent,
                            line.rstrip('\n').rstrip('\r'))
            stream.write(txt)
            stream.write("\n")
    stream.write("\n")
def show_results(prof, stream=None):
    if stream is None:
        stream = sys.stdout
    template = '{0:>6} {1:>12} {2:>12}   {3:<}'

    for code in prof.code_map:
        lines = prof.code_map[code]
        if not lines:
            # .. measurements are empty ..
            continue
        filename = code.co_filename
        if filename.endswith((".pyc", ".pyo")):
            filename = filename[:-1]
        stream.write('Filename: ' + filename + '\n\n')
        if not os.path.exists(filename):
            stream.write('ERROR: Could not find file ' + filename + '\n')
            if filename.startswith("ipython-input"):
                print("NOTE: %mprun can only be used on functions defined in "
                      "physical files, and not in the IPython environment.")
            continue
        all_lines = linecache.getlines(filename)
        sub_lines = inspect.getblock(all_lines[code.co_firstlineno - 1:])
        linenos = range(code.co_firstlineno, code.co_firstlineno +
                        len(sub_lines))
        lines_normalized = {}

        header = template.format('Line #', 'Mem usage', 'Increment',
                                 'Line Contents')
        stream.write(header + '\n')
        stream.write('=' * len(header) + '\n')
        # move everything one frame up
        keys = sorted(lines.keys())

        k_old = keys[0] - 1
        lines_normalized[keys[0] - 1] = lines[keys[0]]
        for i in range(1, len(lines_normalized[keys[0] - 1])):
            lines_normalized[keys[0] - 1][i] = -1.
        k = keys.pop(0)
        while keys:
            lines_normalized[k] = lines[keys[0]]
            for i in range(len(lines_normalized[k_old]),
                           len(lines_normalized[k])):
                lines_normalized[k][i] = -1.
            k_old = k
            k = keys.pop(0)

        first_line = sorted(lines_normalized.keys())[0]
        mem_old = max(lines_normalized[first_line])
        for i, l in enumerate(linenos):
            mem = ''
            inc = ''
            if l in lines_normalized:
                mem = max(lines_normalized[l])
                inc = mem - mem_old
                mem_old = mem
                mem = '{0:9.2f} MB'.format(mem)
                inc = '{0:9.2f} MB'.format(inc)
            stream.write(template.format(l, mem, inc, sub_lines[i]))
        stream.write('\n\n')
Exemple #22
0
 def getsourcelines(self, obj):
     lines, lineno = inspect.findsource(obj)
     if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
         # must be a module frame: do not try to cut a block out of it
         return lines, 1
     elif inspect.ismodule(obj):
         return lines, 1
     return inspect.getblock(lines[lineno:]), lineno + 1
Exemple #23
0
 def getsourcelines(self, obj):
     lines, lineno = inspect.findsource(obj)
     if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
         # must be a module frame: do not try to cut a block out of it
         return lines, 1
     elif inspect.ismodule(obj):
         return lines, 1
     return inspect.getblock(lines[lineno:]), lineno + 1
def get_source_from_func(filename,first_line_num):
    "see python's inspect.py"
    import inspect
    lines = inspect.linecache.getlines(filename)
    line_num = first_line_num - 1
    while line_num > 0:
        if func_definition.match(lines[line_num]):
            break
        lnum = lnum - 1
    return '\n'.join(inspect.getblock(lines[line_num:]))
Exemple #25
0
def get_source_code(func, func_runtime_name, firstlineno):
    lines = linecache.getlines(func.__code__.co_filename)
    code_lines = getblock(lines[firstlineno:])
    # repalce function name
    code_lines[0] = code_lines[0].replace(func.__name__, func_runtime_name, 1)
    i_indent = code_lines[0].index("def")
    # code indentation
    code_lines = [line[i_indent:] for line in code_lines]
    code = ''.join(code_lines)
    return code
Exemple #26
0
def get_func_code(func):
    """ Attempts to retrieve a reliable function code hash.

        The reason we don't use inspect.getsource is that it caches the
        source, whereas we want this to be modified on the fly when the
        function is modified.

        Returns
        -------
        func_code: string
            The function code
        source_file: string
            The path to the file in which the function is defined.
        first_line: int
            The first line of the code in the source file.

        Notes
        ------
        This function does a bit more magic than inspect, and is thus
        more robust.
    """
    source_file = None
    try:
        code = func.__code__
        source_file = code.co_filename
        if not os.path.exists(source_file):
            # Use inspect for lambda functions and functions defined in an
            # interactive shell, or in doctests
            source_code = ''.join(inspect.getsourcelines(func)[0])
            line_no = 1
            if source_file.startswith('<doctest '):
                source_file, line_no = re.match(
                            '\<doctest (.*\.rst)\[(.*)\]\>',
                            source_file).groups()
                line_no = int(line_no)
                source_file = '<doctest %s>' % source_file
            return source_code, source_file, line_no
        # Try to retrieve the source code.
        with open_py_source(source_file) as source_file_obj:
            first_line = code.co_firstlineno
            # All the lines after the function definition:
            source_lines = list(islice(source_file_obj, first_line - 1, None))
        return ''.join(inspect.getblock(source_lines)), source_file, first_line
    except:
        # If the source code fails, we use the hash. This is fragile and
        # might change from one session to another.
        if hasattr(func, '__code__'):
            # Python 3.X
            return str(func.__code__.__hash__()), source_file, -1
        else:
            # Weird objects like numpy ufunc don't have __code__
            # This is fragile, as quite often the id of the object is
            # in the repr, so it might not persist across sessions,
            # however it will work for ufuncs.
            return repr(func), source_file, -1
Exemple #27
0
def get_func_code(func):
    """ Attempts to retrieve a reliable function code hash.

        The reason we don't use inspect.getsource is that it caches the
        source, whereas we want this to be modified on the fly when the
        function is modified.

        Returns
        -------
        func_code: string
            The function code
        source_file: string
            The path to the file in which the function is defined.
        first_line: int
            The first line of the code in the source file.

        Notes
        ------
        This function does a bit more magic than inspect, and is thus
        more robust.
    """
    source_file = None
    try:
        code = func.__code__
        source_file = code.co_filename
        if not os.path.exists(source_file):
            # Use inspect for lambda functions and functions defined in an
            # interactive shell, or in doctests
            source_code = ''.join(inspect.getsourcelines(func)[0])
            line_no = 1
            if source_file.startswith('<doctest '):
                source_file, line_no = re.match(
                            '\<doctest (.*\.rst)\[(.*)\]\>',
                            source_file).groups()
                line_no = int(line_no)
                source_file = '<doctest %s>' % source_file
            return source_code, source_file, line_no
        # Try to retrieve the source code.
        with open_py_source(source_file) as source_file_obj:
            first_line = code.co_firstlineno
            # All the lines after the function definition:
            source_lines = list(islice(source_file_obj, first_line - 1, None))
        return ''.join(inspect.getblock(source_lines)), source_file, first_line
    except:
        # If the source code fails, we use the hash. This is fragile and
        # might change from one session to another.
        if hasattr(func, '__code__'):
            # Python 3.X
            return str(func.__code__.__hash__()), source_file, -1
        else:
            # Weird objects like numpy ufunc don't have __code__
            # This is fragile, as quite often the id of the object is
            # in the repr, so it might not persist across sessions,
            # however it will work for ufuncs.
            return repr(func), source_file, -1
Exemple #28
0
def show_func(filename, start_lineno, func_name, timings, unit, stream=None, stripzeros=False):
    """ Show results for a single function.
    """
    if stream is None:
        stream = sys.stdout

    template = '%6s %9s %12s %8s %8s  %-s'
    d = {}
    total_time = 0.0
    linenos = []
    for lineno, nhits, time in timings:
        total_time += time
        linenos.append(lineno)

    if stripzeros and total_time == 0:
        return

    stream.write("Total time: %g s\n" % (total_time * unit))
    if os.path.exists(filename) or filename.startswith("<ipython-input-"):
        stream.write("File: %s\n" % filename)
        stream.write("Function: %s at line %s\n" % (func_name, start_lineno))
        if os.path.exists(filename):
            # Clear the cache to ensure that we get up-to-date results.
            linecache.clearcache()
        all_lines = linecache.getlines(filename)
        sublines = inspect.getblock(all_lines[start_lineno-1:])
    else:
        stream.write("\n")
        stream.write("Could not find file %s\n" % filename)
        stream.write("Are you sure you are running this program from the same directory\n")
        stream.write("that you ran the profiler from?\n")
        stream.write("Continuing without the function's contents.\n")
        # Fake empty lines so we can see the timings, if not the code.
        nlines = max(linenos) - min(min(linenos), start_lineno) + 1
        sublines = [''] * nlines
    for lineno, nhits, time in timings:
        d[lineno] = (nhits, time, '%5.1f' % (float(time) / nhits),
            '%5.1f' % (100*time / total_time))
    linenos = range(start_lineno, start_lineno + len(sublines))
    empty = ('', '', '', '')
    header = template % ('Line #', 'Hits', 'Time', 'Per Hit', '% Time',
        'Line Contents')
    stream.write("\n")
    stream.write(header)
    stream.write("\n")
    stream.write('=' * len(header))
    stream.write("\n")
    for lineno, line in zip(linenos, sublines):
        nhits, time, per_hit, percent = d.get(lineno, empty)
        txt = template % (lineno, nhits, time, per_hit, percent,
                          line.rstrip('\n').rstrip('\r'))
        stream.write(txt)
        stream.write("\n")
    stream.write("\n")
Exemple #29
0
    def __init__(self, *args, **kwds):
        self._long_opts = kwds.get('long_opts', {})
        self._short_opts = kwds.get('short_opts', {})

        f = self.__filter
        c = self.__convert
        p = self.__pattern

        classes = dict(
            (c(t), getattr(self, n)) for (n, t) in [
                (n, p.findall(n)) for n in filter(f, dir(self))
            ]
        )

        names = dict((v.__name__, k) for (k, v) in classes.items())

        cls = self.__class__
        classname = cls.__name__
        filename = inspect.getsourcefile(cls)
        lines = linecache.getlines(filename)
        lines_len = len(lines)
        prefix = 'class %s(' % classname
        found = False
        for i in range(lines_len):
            line = lines[i]
            if prefix in line:
                found = i
                break

        if not found:
            raise IOError('could not find source code for class')

        block = inspect.getblock(lines[found:])
        text = ''.join(block)
        inner = self.__inner_classes_pattern

        order = [
            (i, names[n[0]]) for (i, n) in enumerate(inner.findall(text))
        ]

        instances = {
            name: cls(self, name)
                for (cls, name) in [
                    (classes[name], name)
                        for (_, name) in order
                ]
        }

        self._invariants = instances
        self._invariant_names = names
        self._invariant_order = order
        self._invariant_classes = classes

        self._invariants_processed = list()
Exemple #30
0
    def __init__(self, *args, **kwds):
        self._long_opts = kwds.get('long_opts', {})
        self._short_opts = kwds.get('short_opts', {})

        f = self.__filter
        c = self.__convert
        p = self.__pattern

        classes = dict(
            (c(t), getattr(self, n)) for (n, t) in [
                (n, p.findall(n)) for n in filter(f, dir(self))
            ]
        )

        names = dict((v.__name__, k) for (k, v) in classes.items())

        cls = self.__class__
        classname = cls.__name__
        filename = inspect.getsourcefile(cls)
        lines = linecache.getlines(filename)
        lines_len = len(lines)
        prefix = 'class %s(' % classname
        found = False
        for i in range(lines_len):
            line = lines[i]
            if prefix in line:
                found = i
                break

        if not found:
            raise IOError('could not find source code for class')

        block = inspect.getblock(lines[found:])
        text = ''.join(block)
        inner = self.__inner_classes_pattern

        order = [
            (i, names[n[0]]) for (i, n) in enumerate(inner.findall(text))
        ]

        instances = {
            name: cls(self, name)
                for (cls, name) in [
                    (classes[name], name)
                        for (_, name) in order
                ]
        }

        self._invariants = instances
        self._invariant_names = names
        self._invariant_order = order
        self._invariant_classes = classes

        self._invariants_processed = list()
Exemple #31
0
def inspect_generator(g):
    sourcecode = open(g.gi_code.co_filename).readlines()
    gline = g.gi_code.co_firstlineno
    generator_code = inspect.getblock(sourcecode[gline-1:])

    output = "Generator %r from %r\n" % (g.gi_code.co_name, g.gi_code.co_filename)
    output += "".join("%4s: %s" % (idx+gline, line) for idx, line in enumerate(generator_code))

    output += "Local variables:\n"
    output += "".join("%s = %r\n" % (key,value) for key,value in g.gi_frame.f_locals.items())

    return output
Exemple #32
0
def getsourcelines(pyObject):
    """Return a list of source lines and starting line number for an object.

    The argument may be a module, class, method, function, traceback, frame,
    or code object.  The source code is returned as a list of the lines
    corresponding to the object and the line number indicates where in the
    original source file the first line of code was found.  An IOError is
    raised if the source code cannot be retrieved."""
    lines, lnum = findsource(pyObject)

    if ismodule(pyObject): return lines, 0
    else: return getblock(lines[lnum:]), lnum + 1
Exemple #33
0
def show_func(filename, start_lineno, func_name, timings, unit):
    """ Show results for a single function.
    """

    d = {}
    total_time = 0.0
    linenos = []
    for lineno, nhits, time in timings:
        total_time += time
        linenos.append(lineno)

    if total_time == 0:
        return False

    retval = {}

    retval['Total time'] = "%g s" % (total_time * unit)
    if os.path.exists(filename) or filename.startswith("<ipython-input-"):
        retval['File'] = filename
        retval['Function'] = '%s at line %s' % (func_name, start_lineno)
        if os.path.exists(filename):
            # Clear the cache to ensure that we get up-to-date results.
            linecache.clearcache()
        all_lines = linecache.getlines(filename)
        sublines = inspect.getblock(all_lines[start_lineno-1:])
    else:
        # Fake empty lines so we can see the timings, if not the code.
        nlines = max(linenos) - min(min(linenos), start_lineno) + 1
        sublines = [''] * nlines

    for lineno, nhits, time in timings:
        d[lineno] = (nhits, time, '%5.1f' % (float(time) / nhits),
            '%5.1f' % (100*time / total_time))
    linenos = range(start_lineno, start_lineno + len(sublines))
    empty = ('', '', '', '')
    lines = []
    for lineno, line in zip(linenos, sublines):
        nhits, time, per_hit, percent = d.get(lineno, empty)
        line = {
                'Line #': lineno,
                'Hits': nhits,
                'Time': time,
                'Per Hit': per_hit,
                '% Time': percent,
                'Line Contents': line.rstrip('\n').rstrip('\r')
                }
        lines.append(line)

    retval['lines'] = lines
    return retval
def show_results(prof, stream=None):

    if stream is None:
        stream = sys.stdout
    template = '{0:>6} {1:>12} {2:>10}   {3:<}'
    header = template.format('Line #', 'Mem usage', 'Increment', 'Line Contents')
    stream.write(header + '\n')
    stream.write('=' * len(header) + '\n')

    for code in prof.code_map:
        lines = prof.code_map[code]
        if not lines:
            # .. measurements are empty ..
            continue
        filename = code.co_filename
        if (filename.endswith(".pyc") or
            filename.endswith(".pyo")):
            filename = filename[:-1]
        all_lines = linecache.getlines(filename)
        sub_lines = inspect.getblock(all_lines[code.co_firstlineno-1:])
        linenos = range(code.co_firstlineno, code.co_firstlineno + len(sub_lines))
        lines_normalized = {}

        # move everything one frame up
        keys = sorted(lines.keys())

        k_old = keys[0] - 1
        lines_normalized[keys[0] - 1] = lines[keys[0]]
        k = keys.pop(0)
        while keys:
            lines_normalized[k] = lines[keys[0]]
            for i in range(len(lines_normalized[k_old]), len(lines_normalized[k])):
                lines_normalized[k][i] = -1.
            k_old = k
            k = keys.pop(0)

        first_line = sorted(lines_normalized.keys())[0]
        mem_old = max(lines_normalized[first_line])
        for l in linenos:
            mem = ''
            inc = ''
            if l in lines_normalized:
                mem = max(lines_normalized[l])
                inc = mem - mem_old
                mem_old = mem
                mem = '{0:5.2f} MB'.format(mem)
                inc = '{0:5.2f} MB'.format(inc)
            line = linecache.getline(filename, l)
            stream.write(template.format(l, mem, inc, line))
        stream.write('\n')
Exemple #35
0
def process_line_stats(line_stats):
    "Converts line_profiler.LineStats instance into something more useful"

    profile_results = []

    if not line_stats:
        return profile_results

    # We want timings in ms (instead of CPython's microseconds)
    multiplier = line_stats.unit / 1e-3

    for key, timings in sorted(line_stats.timings.items()):
        if not timings:
            continue

        filename, start_lineno, func_name = key

        all_lines = linecache.getlines(filename)
        sublines = inspect.getblock(all_lines[start_lineno - 1:])
        end_lineno = start_lineno + len(sublines)

        line_to_timing = collections.defaultdict(lambda: (-1, 0))

        for (lineno, nhits, time) in timings:
            line_to_timing[lineno] = (nhits, time)

        padded_timings = []

        for lineno in range(start_lineno, end_lineno):
            nhits, time = line_to_timing[lineno]
            padded_timings.append((lineno, nhits, time))

        profile_results.append({
            'filename':
            filename,
            'start_lineno':
            start_lineno,
            'func_name':
            func_name,
            'timings': [(
                lineno,
                all_lines[lineno - 1],
                time * multiplier,
                nhits,
            ) for (lineno, nhits, time) in padded_timings],
            'total_time':
            sum([time for _, _, time in timings]) * multiplier
        })

    return profile_results
 def get_source(self, filename, first_line_num):
     '''see python's inspect.py - this gets the source from
     a Python source file, given the file name and first line number'''
     import inspect
     try:
         lines = inspect.linecache.getlines(filename)
         line_num = first_line_num - 1
         while line_num > 0:
             if self.func_definition_re.match(lines[line_num]):
                 break
             lnum = lnum - 1
         return '\n'.join(inspect.getblock(lines[line_num:]))
     except:
         return ''
Exemple #37
0
    def __init__(self, func, sandbox):
        self.path = func.func_code.co_filename
        self.name = func.func_name

        code = func.func_code
        firstlineno = code.co_firstlineno
        lines = sandbox._current_source.splitlines(True)
        lines = inspect.getblock(lines[firstlineno - 1:])

        # The code lines we get out of inspect.getsourcelines look like
        #   @template
        #   def Template(*args, **kwargs):
        #       VAR = 'value'
        #       ...
        func_ast = ast.parse(''.join(lines), self.path)
        # Remove decorators
        func_ast.body[0].decorator_list = []
        # Adjust line numbers accordingly
        ast.increment_lineno(func_ast, firstlineno - 1)

        # When using a custom dictionary for function globals/locals, Cpython
        # actually never calls __getitem__ and __setitem__, so we need to
        # modify the AST so that accesses to globals are properly directed
        # to a dict.
        self._global_name = b'_data' # AST wants str for this, not unicode
        # In case '_data' is a name used for a variable in the function code,
        # prepend more underscores until we find an unused name.
        while (self._global_name in code.co_names or
                self._global_name in code.co_varnames):
            self._global_name += '_'
        func_ast = self.RewriteName(sandbox, self._global_name).visit(func_ast)

        # Execute the rewritten code. That code now looks like:
        #   def Template(*args, **kwargs):
        #       _data['VAR'] = 'value'
        #       ...
        # The result of executing this code is the creation of a 'Template'
        # function object in the global namespace.
        glob = {'__builtins__': sandbox._builtins}
        func = types.FunctionType(
            compile(func_ast, self.path, 'exec'),
            glob,
            self.name,
            func.func_defaults,
            func.func_closure,
        )
        func()

        self._func = glob[self.name]
def process_line_stats(line_stats):
    "Converts line_profiler.LineStats instance into something more useful"

    profile_results = []

    if not line_stats:
        return profile_results

    # We want timings in ms (instead of CPython's microseconds)
    multiplier = line_stats.unit / 1e-3

    for key, timings in sorted(line_stats.timings.items()):
        if not timings:
            continue

        filename, start_lineno, func_name = key

        all_lines = linecache.getlines(filename)
        sublines = inspect.getblock(all_lines[start_lineno-1:])
        end_lineno = start_lineno + len(sublines)

        line_to_timing = collections.defaultdict(lambda: (-1, 0))

        for (lineno, nhits, time) in timings:
            line_to_timing[lineno] = (nhits, time)

        padded_timings = []

        for lineno in range(start_lineno, end_lineno):
            nhits, time = line_to_timing[lineno]
            padded_timings.append( (lineno, nhits, time) )

        profile_results.append({
            'filename': filename,
            'start_lineno': start_lineno,
            'func_name': func_name,
            'timings': [
                (
                    lineno,
                    unicode(all_lines[lineno - 1].decode("utf8")),
                    time * multiplier,
                    nhits,
                ) for (lineno, nhits, time) in padded_timings
            ],
            'total_time': sum([time for _, _, time in timings]) * multiplier
        })

    return profile_results
Exemple #39
0
    def get_in_frame_range(self):
        # find function definition and mark lines
        if hasattr(self.code, 'co_firstlineno'):
            lineno = self.code.co_firstlineno - 1
            while lineno > 0:
                if _funcdef_re.match(self.sourcelines[lineno]):
                    break
                lineno -= 1
            try:
                offset = len(inspect.getblock([x + '\n' for x
                                               in self.sourcelines[lineno:]]))
            except TokenError:
                offset = 0

            return (lineno, lineno + offset)
        return None
    def get_in_frame_range(self):
        # find function definition and mark lines
        if hasattr(self.code, 'co_firstlineno'):
            lineno = self.code.co_firstlineno - 1
            while lineno > 0:
                if _funcdef_re.match(self.sourcelines[lineno]):
                    break
                lineno -= 1
            try:
                offset = len(inspect.getblock([x + '\n' for x
                                               in self.sourcelines[lineno:]]))
            except TokenError:
                offset = 0

            return (lineno, lineno + offset)
        return None
Exemple #41
0
 def get_block(self, filename, start_lineno, strip='\n\r'):
     '''get source code block.  returns empty lines if file not accessable'''
     if not os.path.exists(filename):
         # Fake empty lines so we can see the timings, if not the code.
         nlines = max(self.linenos) - min(min(self.linenos), start_lineno) + 1
         sublines = [''] * nlines
     else:
         # Clear the cache to ensure that we get up-to-date results.
         linecache.clearcache()
         all_lines = linecache.getlines(filename)
         sublines = inspect.getblock(all_lines[start_lineno-1:])
         
         if strip:
             sublines = [l.strip(strip) for l in sublines]
     
     return sublines
def process_line_stats(line_stats):
    profile_results = []

    if not line_stats:
        return profile_results

    multiplier = line_stats.unit / 1e-3

    for key, timings in sorted(line_stats.timings.items()):
        if not timings:
            continue

        filename, start_lineno, func_name = key

        all_lines = linecache.getlines(filename)
        sublines = inspect.getblock(all_lines[start_lineno - 1:])
        end_lineno = start_lineno + len(sublines)

        line_to_timing = collections.defaultdict(lambda: (-1, 0))

        for (lineno, nhits, time) in timings:
            line_to_timing[lineno] = (nhits, time)

        padded_timings = []

        for lineno in range(start_lineno, end_lineno):
            nhits, time = line_to_timing[lineno]
            padded_timings.append((lineno, nhits, time))

        profile_results.append({
            'filename':
            filename,
            'start_lineno':
            start_lineno,
            'func_name':
            func_name,
            'timings': [(
                lineno,
                unicode(all_lines[lineno - 1].decode("utf8")),
                time * multiplier,
                nhits,
            ) for (lineno, nhits, time) in padded_timings],
            'total_time':
            sum([time for _, _, time in timings]) * multiplier
        })

    return profile_results
Exemple #43
0
def get_func_code(func):
    """ Attempts to retrieve a reliable function code hash.

        The reason we don't use inspect.getsource is that it caches the
        source, whereas we want this to be modified on the fly when the
        function is modified.

        Returns
        -------
        func_code: string
            The function code
        source_file: string
            The path to the file in which the function is defined.
        first_line: int
            The first line of the code in the source file.

        Notes
        ------
        This function does a bit more magic than inspect, and is thus
        more robust.
    """
    source_file = None
    try:
        if func.__name__ == '<lambda>':
            # On recent Python version, inspect is reliable with lambda
            source_file = func.__code__.co_filename
            return ''.join(inspect.getsourcelines(func)[0]), source_file, 1
        # Try to retrieve the source code.
        code = func.__code__
        source_file = code.co_filename
        with open(source_file) as source_file_obj:
            first_line = code.co_firstlineno
            # All the lines after the function definition:
            source_lines = list(islice(source_file_obj, first_line - 1, None))
        return ''.join(inspect.getblock(source_lines)), source_file, first_line
    except:
        # If the source code fails, we use the hash. This is fragile and
        # might change from one session to another.
        if hasattr(func, '__code__'):
            # Python 3.X
            return str(func.__code__.__hash__()), source_file, -1
        else:
            # Weird objects like numpy ufunc don't have __code__
            # This is fragile, as quite often the id of the object is
            # in the repr, so it might not persist accross sessions,
            # however it will work for ufuncs.
            return repr(func), source_file, -1
Exemple #44
0
def get_func_code(func):
    """ Attempts to retrieve a reliable function code hash.

        The reason we don't use inspect.getsource is that it caches the
        source, whereas we want this to be modified on the fly when the
        function is modified.

        Returns
        -------
        func_code: string
            The function code
        source_file: string
            The path to the file in which the function is defined.
        first_line: int
            The first line of the code in the source file.

        Notes
        ------
        This function does a bit more magic than inspect, and is thus
        more robust.
    """
    source_file = None
    try:
        if func.__name__ == '<lambda>':
            # On recent Python version, inspect is reliable with lambda
            source_file = func.__code__.co_filename
            return ''.join(inspect.getsourcelines(func)[0]), source_file, 1
        # Try to retrieve the source code.
        code = func.__code__
        source_file = code.co_filename
        with open(source_file) as source_file_obj:
            first_line = code.co_firstlineno
            # All the lines after the function definition:
            source_lines = list(islice(source_file_obj, first_line - 1, None))
        return ''.join(inspect.getblock(source_lines)), source_file, first_line
    except:
        # If the source code fails, we use the hash. This is fragile and
        # might change from one session to another.
        if hasattr(func, '__code__'):
            # Python 3.X
            return str(func.__code__.__hash__()), source_file, -1
        else:
            # Weird objects like numpy ufunc don't have __code__
            # This is fragile, as quite often the id of the object is
            # in the repr, so it might not persist across sessions,
            # however it will work for ufuncs.
            return repr(func), source_file, -1
Exemple #45
0
def show_func(filename, start_lineno, func_name, timings, unit):
    """
    Show results for a single function.
    """
    print "File: %s" % filename
    print "Function: %s at line %s" % (func_name, start_lineno)

    d = {}
    total_time = 0.0
    linenos = []

    for lineno, nhits, time in timings:
        total_time += time
        linenos.append(lineno)

    #print "Total time: %g s" % (total_time * unit)

    if not os.path.exists(filename):
        raise Exception("Could not find file %s" % filename)
        # Fake empty lines so we can see the timings, if not the code.
        nlines = max(linenos) - min(min(linenos), start_lineno) + 1
        sublines = [''] * nlines
    else:
        all_lines = linecache.getlines(filename)
        sublines = inspect.getblock(all_lines[start_lineno-1:])

    for lineno, nhits, time in timings:
        d[lineno] = (
            nhits,
            '%2.3f s' % (time * unit),
            '%5.1f' % (float(time) / nhits),
            '%5.1f' % (100*time / total_time)
        )

    linenos = range(start_lineno, start_lineno + len(sublines))

    empty = ('', '', '', '')

    # ('Line #', 'Hits', 'Time', 'Per Hit', '% Time', 'Line Contents')

    results = []

    for lineno, line in zip(linenos, sublines):
        nhits, time, per_hit, percent = d.get(lineno, empty)
        results.append((lineno, nhits, time, per_hit, percent,
            line.rstrip('\n').rstrip('\r')))
    return results
Exemple #46
0
def show_results(prof, stream=None, precision=1):
    if stream is None:
        stream = sys.stdout
    template = '{0:>6} {1:>12} {2:>12}   {3:<}'

    for code in prof.code_map:
        lines = prof.code_map[code]
        if not lines:
            # .. measurements are empty ..
            continue
        filename = code.co_filename
        if filename.endswith((".pyc", ".pyo")):
            filename = filename[:-1]
        stream.write('Filename: ' + filename + '\n\n')
        if not os.path.exists(filename):
            stream.write('ERROR: Could not find file ' + filename + '\n')
            if any([
                    filename.startswith(k)
                    for k in ("ipython-input", "<ipython-input")
            ]):
                print("NOTE: %mprun can only be used on functions defined in "
                      "physical files, and not in the IPython environment.")
            continue
        all_lines = linecache.getlines(filename)
        sub_lines = inspect.getblock(all_lines[code.co_firstlineno - 1:])
        linenos = range(code.co_firstlineno,
                        code.co_firstlineno + len(sub_lines))

        header = template.format('Line #', 'Mem usage', 'Increment',
                                 'Line Contents')
        stream.write(header + '\n')
        stream.write('=' * len(header) + '\n')

        mem_old = lines[min(lines.keys())]
        float_format = '{0}.{1}f'.format(precision + 4, precision)
        template_mem = '{0:' + float_format + '} MiB'
        for line in linenos:
            mem = ''
            inc = ''
            if line in lines:
                mem = lines[line]
                inc = mem - mem_old
                mem_old = mem
                mem = template_mem.format(mem)
                inc = template_mem.format(inc)
            stream.write(template.format(line, mem, inc, all_lines[line - 1]))
        stream.write('\n\n')
Exemple #47
0
def _extract_source(lines, lineno):
    r"""
    Given a list of lines or a multiline string and a starting lineno,
    _extract_source returns [source_lines].  [source_lines] is the smallest
    indentation block starting at lineno.
    """
    if lineno < 1:
        raise ValueError, "Line numbering starts at 1! (tried to extract line %s)" % lineno
    lineno -= 1

    if isinstance(lines, str):
        lines = lines.splitlines(True)  # true keeps the '\n'
    if len(lines) > 0:
        # Fixes an issue with getblock
        lines[-1] += '\n'

    return inspect.getblock(lines[lineno:])
def _memory_profile_it(mem_profiler):
   """ Returns a dictionary with the memory profile result

   Args:
      mem_profiler (class): instance of `SpeedIT.MemIt._LineMemoryProfiler`

   Returns:
      tuple: format: (max_mem, table): table = list_of_dictionaries
   """
   memory_precision = 3
   table = []
   max_mem = 0
   for code in mem_profiler.code_map:
      lines = mem_profiler.code_map[code]

      if not lines:
         # .. measurements are empty ..
         continue
      filename = code.co_filename
      if filename.endswith(('.pyc', '.pyo')):
         filename = filename[:-1]
      if not path.exists(filename):
         print('\n_memory_profile_it() ERROR: Could not find file: {}'.format(filename))
         continue
      all_lines = getlines(filename)
      sub_lines = getblock(all_lines[code.co_firstlineno - 1:])
      mem_old = lines[min(lines.keys())]
      for line in range(code.co_firstlineno, code.co_firstlineno + len(sub_lines)):
         mem = 0.0
         mem_increment = 0.0
         if line in lines:
            mem = lines[line]
            if mem > max_mem:
               max_mem = mem
            mem_increment = mem - mem_old
            mem_old = mem
         dict_ = {
            'line_num': '{}'.format(line),
            'memory_usage': '{:.{}f} MiB'.format(mem, memory_precision),
            'increment_memory_usage': '{:.{}f} MiB'.format(mem_increment, memory_precision),
            'line': all_lines[line - 1].strip()
         }
         table.append(dict_)

   max_mem = '{:.{}f} MiB'.format(max_mem, memory_precision)
   return max_mem, table
def _extract_source(lines, lineno):
    r"""
    Given a list of lines or a multiline string and a starting lineno,
    _extract_source returns [source_lines].  [source_lines] is the smallest
    indentation block starting at lineno.
    """
    if lineno < 1:
        raise ValueError, "Line numbering starts at 1! (tried to extract line %s)" % lineno
    lineno -= 1
    
    if isinstance(lines, str):
        lines = lines.splitlines(True) # true keeps the '\n'
    if len(lines) > 0:
        # Fixes an issue with getblock
        lines[-1] += '\n'

    return inspect.getblock(lines[lineno:])
Exemple #50
0
 def fix_single(match, lines, lineno):
     if not lines[lineno + 1].startswith("def"):
         return
     block_lines = inspect.getblock(lines[lineno + 1 :])
     func_code = "".join(block_lines)
     if func_code[0].isspace():
         node = ast.parse("if 1:\n" + func_code).body[0].body
     else:
         node = ast.parse(func_code).body[0]
     response_param_name = looks_like_teardown_function(node)
     if response_param_name is None:
         return
     before = lines[:lineno]
     decorator = [match.group(1) + match.group(2).replace("after_", "teardown_") + match.group(3)]
     body = [line.replace(response_param_name, "exception") for line in block_lines if not is_return_line(line)]
     after = lines[lineno + len(block_lines) + 1 :]
     return before + decorator + body + after
def getsource_no_unwrap(obj):
  """Return source code for an object. Does not unwrap TFDecorators.

  The source code is returned literally, including indentation for functions not
  at the top level. This function is analogous to inspect.getsource, with one
  key difference - it doesn't unwrap decorators. For simplicity, support for
  some Python object types is dropped (tracebacks, frames, code objects).

  Args:
      obj: a class, method, or function object.

  Returns:
      source code as a string

  """
  lines, lnum = _inspect.findsource(obj)
  return ''.join(_inspect.getblock(lines[lnum:]))
def getsource_no_unwrap(obj):
    """Return source code for an object. Does not unwrap TFDecorators.

  The source code is returned literally, including indentation for functions not
  at the top level. This function is analogous to inspect.getsource, with one
  key difference - it doesn't unwrap decorators. For simplicity, support for
  some Python object types is dropped (tracebacks, frames, code objects).

  Args:
      obj: a class, method, or function object.

  Returns:
      source code as a string

  """
    lines, lnum = _inspect.findsource(obj)
    return ''.join(_inspect.getblock(lines[lnum:]))
Exemple #53
0
def getsource(func):
    """ Returning source code for a decoratted function.

        inspect.getsource fails on decoratted functions, hence, a more elaborate
        way to retrieve the source-code of such functions

        Parameters:
        -----------
        func: function object

    """

    # Obtain the module of the function
    module = inspect.getmodule(func)

    # Get the source lines of the file containing the module
    file = inspect.getsourcefile(module)
    lines = linecache.getlines(file)
    object = func.func_code

    # Using regular expressions find the lines of the source-code that
    # represent the function
    lnum = len(lines) - 1
    pat = re.compile(r'^(\s*def\s%s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)' %
                     func.__name__)

    found, source, code_object = 0, '', None
    while lnum >= 0 and found == 0:
        if pat.match(lines[lnum]):
            new_lines = inspect.getblock(lines[lnum:])
            source = string.join(new_lines, '')

            # Check if this is the right function, as reg-ex matches the
            # line with decorator definitions, i.e., @decorator-name, too.
            code_object = compiler.compile(source, '', 'exec')
            if func.__name__ in code_object.co_varnames:
                found = 1

        lnum = lnum - 1

    # Return the source code of the function block
    if found:
        return source
    else:
        return None
def show_results(prof, stream=None, precision=1):
    if stream is None:
        stream = sys.stdout
    template = '{0:>6} {1:>12} {2:>12}   {3:<}'

    for code in prof.code_map:
        lines = prof.code_map[code]
        if not lines:
            # .. measurements are empty ..
            continue
        filename = code.co_filename
        if filename.endswith((".pyc", ".pyo")):
            filename = filename[:-1]
        stream.write('Filename: ' + filename + '\n\n')
        if not os.path.exists(filename):
            stream.write('ERROR: Could not find file ' + filename + '\n')
            if any([filename.startswith(k) for k in
                    ("ipython-input", "<ipython-input")]):
                print("NOTE: %mprun can only be used on functions defined in "
                      "physical files, and not in the IPython environment.")
            continue
        all_lines = linecache.getlines(filename)
        sub_lines = inspect.getblock(all_lines[code.co_firstlineno - 1:])
        linenos = range(code.co_firstlineno,
                        code.co_firstlineno + len(sub_lines))

        header = template.format('Line #', 'Mem usage', 'Increment',
                                 'Line Contents')
        stream.write(header + '\n')
        stream.write('=' * len(header) + '\n')

        mem_old = lines[min(lines.keys())]
        float_format = '{0}.{1}f'.format(precision + 4, precision)
        template_mem = '{0:' + float_format + '} MiB'
        for line in linenos:
            mem = ''
            inc = ''
            if line in lines:
                mem = lines[line]
                inc = mem - mem_old
                mem_old = mem
                mem = template_mem.format(mem)
                inc = template_mem.format(inc)
            stream.write(template.format(line, mem, inc, all_lines[line - 1]))
        stream.write('\n\n')
Exemple #55
0
def show_func(filename, start_lineno, func_name, timings, unit, stream=None):
    """ Show results for a single function.
    """
    if not timings:
        return
    if stream is None:
        stream = sys.stdout
    print >> stream, "File: %s" % filename
    print >> stream, "Function: %s at line %s" % (func_name, start_lineno)
    template = '%6s %9s %12s %8s %8s  %-s'
    d = {}
    total_time = 0.0
    linenos = []
    for lineno, nhits, time in timings:
        total_time += time
        linenos.append(lineno)
    print >> stream, "Total time: %g s" % (total_time * unit)
    if not os.path.exists(filename):
        print >> stream, ""
        print >> stream, "Could not find file %s" % filename
        print >> stream, "Are you sure you are running this program from the same directory"
        print >> stream, "that you ran the profiler from?"
        print >> stream, "Continuing without the function's contents."
        # Fake empty lines so we can see the timings, if not the code.
        nlines = max(linenos) - min(min(linenos), start_lineno) + 1
        sublines = [''] * nlines
    else:
        all_lines = linecache.getlines(filename)
        sublines = inspect.getblock(all_lines[start_lineno - 1:])
    for lineno, nhits, time in timings:
        d[lineno] = (nhits, time, '%5.1f' % (float(time) / nhits),
                     '%5.1f' % (100 * time / total_time))
    linenos = range(start_lineno, start_lineno + len(sublines))
    empty = ('', '', '', '')
    header = template % ('Line #', 'Hits', 'Time', 'Per Hit', '% Time',
                         'Line Contents')
    print >> stream, ""
    print >> stream, header
    print >> stream, '=' * len(header)
    for lineno, line in zip(linenos, sublines):
        nhits, time, per_hit, percent = d.get(lineno, empty)
        print >> stream, template % (lineno, nhits, time, per_hit, percent,
                                     line.rstrip('\n').rstrip('\r'))
    print >> stream, ""
Exemple #56
0
def show_func(filename, start_lineno, func_name, timings, unit):
    """
    Show results for a single function.
    """
    print "File: %s" % filename
    print "Function: %s at line %s" % (func_name, start_lineno)

    d = {}
    total_time = 0.0
    linenos = []

    for lineno, nhits, time in timings:
        total_time += time
        linenos.append(lineno)

    #print "Total time: %g s" % (total_time * unit)

    if not os.path.exists(filename):
        raise Exception("Could not find file %s" % filename)
        # Fake empty lines so we can see the timings, if not the code.
        nlines = max(linenos) - min(min(linenos), start_lineno) + 1
        sublines = [''] * nlines
    else:
        all_lines = linecache.getlines(filename)
        sublines = inspect.getblock(all_lines[start_lineno - 1:])

    for lineno, nhits, time in timings:
        d[lineno] = (nhits, '%2.3f s' % (time * unit),
                     '%5.1f' % (float(time) / nhits),
                     '%5.1f' % (100 * time / total_time))

    linenos = range(start_lineno, start_lineno + len(sublines))

    empty = ('', '', '', '')

    # ('Line #', 'Hits', 'Time', 'Per Hit', '% Time', 'Line Contents')

    results = []

    for lineno, line in zip(linenos, sublines):
        nhits, time, per_hit, percent = d.get(lineno, empty)
        results.append((lineno, nhits, time, per_hit, percent,
                        line.rstrip('\n').rstrip('\r')))
    return results
Exemple #57
0
def ast_from_source(source, keyword: str):
    """
    Return the AST representation of `source`.  `source` might be a function or
    string of source code.

    If `source` is a function, `keyword` is used to find the very start of its
    source code.
    """
    if inspect.isfunction(source):
        lines, lnum = inspect.findsource(source.__code__)

        # Append line-ending if necessary
        for idx in range(len(lines)):
            if not lines[idx].endswith("\n"):
                lines[idx] += "\n"

        # Lines starting from `lnum` may contain enclosing tokens of previous expression
        # We use `keyword` to locate the true start point of source
        while True:
            first_keyword_loc = lines[lnum].find(keyword)
            if first_keyword_loc >= 0:
                break
            lnum -= 1

        lines = [lines[lnum][first_keyword_loc:]] + lines[lnum + 1:]
        # Prepend the lines with newlines, so that parsed AST will have correct lineno
        source_lines = ["\n"] * lnum + inspect.getblock(lines)
        source = "".join(source_lines)

    # Some garbage may still remain at the end, we alternatively try compiling
    # and popping the last character until the source is valid.
    exc = None
    original_source = source
    while source:
        try:
            return ast.parse(source).body[0]
        except SyntaxError as e:
            source = source[:-1]
            exc = e
    else:
        # This should never happen
        raise RuntimeError("cannot parse the snippet into AST:\n{}".format(
            original_source)) from exc
    def _update_code(self, module_source):
        """ Regenerate the code for the function.
        """
        # This isn't quite right as it will omit comments above the function.
        #  Need to scan upwards from the function.

        ast = compile(module_source, '', 'exec', _ast.PyCF_ONLY_AST)
        lineno = -1
        for node in ast.body:
            if isinstance(node, _ast.FunctionDef) and node.name == self.name:
                lineno = node.lineno

        if lineno >= 0:
            codelines = module_source.split('\n')
            codelines = [codeline + '\n' for codeline in codelines]
            self.code = ''.join(inspect.getblock(codelines[lineno-1:]))
        else:
            self.code = ''
        return