~ubuntu-branches/debian/sid/kdevelop/sid

« back to all changes in this revision

Viewing changes to languages/python/kde_inspect.py

  • Committer: Bazaar Package Importer
  • Author(s): Jeremy Lainé
  • Date: 2006-05-23 18:39:42 UTC
  • Revision ID: james.westby@ubuntu.com-20060523183942-hucifbvh68k2bwz7
Tags: upstream-3.3.2
Import upstream version 3.3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""Get useful information from live Python objects.
 
2
 
 
3
This module encapsulates the interface provided by the internal special
 
4
attributes (func_*, co_*, im_*, tb_*, etc.) in a friendlier fashion.
 
5
It also provides some help for examining source code and class layout.
 
6
 
 
7
Here are some of the useful functions provided by this module:
 
8
 
 
9
    ismodule(), isclass(), ismethod(), isfunction(), istraceback(),
 
10
        isframe(), iscode(), isbuiltin(), isroutine() - check object types
 
11
    getmembers() - get members of an object that satisfy a given condition
 
12
 
 
13
    getfile(), getsourcefile(), getsource() - find an object's source code
 
14
    getdoc(), getcomments() - get documentation on an object
 
15
    getmodule() - determine the module that an object came from
 
16
    getclasstree() - arrange classes so as to represent their hierarchy
 
17
 
 
18
    getargspec(), getargvalues() - get info about function arguments
 
19
    formatargspec(), formatargvalues() - format an argument spec
 
20
    getouterframes(), getinnerframes() - get info about frames
 
21
    currentframe() - get the current stack frame
 
22
    stack(), trace() - get info about frames on the stack or in a traceback
 
23
"""
 
24
 
 
25
# This module is in the public domain.  No warranties.
 
26
 
 
27
__version__ = 'Ka-Ping Yee <ping@lfw.org>, 1 Jan 2001'
 
28
 
 
29
import sys, types, string, dis, imp, tokenize
 
30
 
 
31
# ----------------------------------------------------------- type-checking
 
32
def ismodule(object):
 
33
    """Return true if the object is a module.
 
34
 
 
35
    Module objects provide these attributes:
 
36
        __doc__         documentation string
 
37
        __file__        filename (missing for built-in modules)"""
 
38
    return type(object) is types.ModuleType
 
39
 
 
40
def isclass(object):
 
41
    """Return true if the object is a class.
 
42
 
 
43
    Class objects provide these attributes:
 
44
        __doc__         documentation string
 
45
        __module__      name of module in which this class was defined"""
 
46
    return type(object) is types.ClassType
 
47
 
 
48
def ismethod(object):
 
49
    """Return true if the object is an instance method.
 
50
 
 
51
    Instance method objects provide these attributes:
 
52
        __doc__         documentation string
 
53
        __name__        name with which this method was defined
 
54
        im_class        class object in which this method belongs
 
55
        im_func         function object containing implementation of method
 
56
        im_self         instance to which this method is bound, or None"""
 
57
    return type(object) is types.MethodType
 
58
 
 
59
def isfunction(object):
 
60
    """Return true if the object is a user-defined function.
 
61
 
 
62
    Function objects provide these attributes:
 
63
        __doc__         documentation string
 
64
        __name__        name with which this function was defined
 
65
        func_code       code object containing compiled function bytecode
 
66
        func_defaults   tuple of any default values for arguments
 
67
        func_doc        (same as __doc__)
 
68
        func_globals    global namespace in which this function was defined
 
69
        func_name       (same as __name__)"""
 
70
    return type(object) in [types.FunctionType, types.LambdaType]
 
71
 
 
72
def istraceback(object):
 
73
    """Return true if the object is a traceback.
 
74
 
 
75
    Traceback objects provide these attributes:
 
76
        tb_frame        frame object at this level
 
77
        tb_lasti        index of last attempted instruction in bytecode
 
78
        tb_lineno       current line number in Python source code
 
79
        tb_next         next inner traceback object (called by this level)"""
 
80
    return type(object) is types.TracebackType
 
81
 
 
82
def isframe(object):
 
83
    """Return true if the object is a frame object.
 
84
 
 
85
    Frame objects provide these attributes:
 
86
        f_back          next outer frame object (this frame's caller)
 
87
        f_builtins      built-in namespace seen by this frame
 
88
        f_code          code object being executed in this frame
 
89
        f_exc_traceback traceback if raised in this frame, or None
 
90
        f_exc_type      exception type if raised in this frame, or None
 
91
        f_exc_value     exception value if raised in this frame, or None
 
92
        f_globals       global namespace seen by this frame
 
93
        f_lasti         index of last attempted instruction in bytecode
 
94
        f_lineno        current line number in Python source code
 
95
        f_locals        local namespace seen by this frame
 
96
        f_restricted    0 or 1 if frame is in restricted execution mode
 
97
        f_trace         tracing function for this frame, or None"""
 
98
    return type(object) is types.FrameType
 
99
 
 
100
def iscode(object):
 
101
    """Return true if the object is a code object.
 
102
 
 
103
    Code objects provide these attributes:
 
104
        co_argcount     number of arguments (not including * or ** args)
 
105
        co_code         string of raw compiled bytecode
 
106
        co_consts       tuple of constants used in the bytecode
 
107
        co_filename     name of file in which this code object was created
 
108
        co_firstlineno  number of first line in Python source code
 
109
        co_flags        bitmap: 1=optimized | 2=newlocals | 4=*arg | 8=**arg
 
110
        co_lnotab       encoded mapping of line numbers to bytecode indices
 
111
        co_name         name with which this code object was defined
 
112
        co_names        tuple of names of local variables
 
113
        co_nlocals      number of local variables
 
114
        co_stacksize    virtual machine stack space required
 
115
        co_varnames     tuple of names of arguments and local variables"""
 
116
    return type(object) is types.CodeType
 
117
 
 
118
def isbuiltin(object):
 
119
    """Return true if the object is a built-in function or method.
 
120
 
 
121
    Built-in functions and methods provide these attributes:
 
122
        __doc__         documentation string
 
123
        __name__        original name of this function or method
 
124
        __self__        instance to which a method is bound, or None"""
 
125
    return type(object) in [types.BuiltinFunctionType,
 
126
                            types.BuiltinMethodType]
 
127
 
 
128
def isroutine(object):
 
129
    """Return true if the object is any kind of function or method."""
 
130
    return type(object) in [types.FunctionType, types.LambdaType,
 
131
                            types.MethodType, types.BuiltinFunctionType,
 
132
                            types.BuiltinMethodType]
 
133
 
 
134
def getmembers(object, predicate=None):
 
135
    """Return all members of an object as (name, value) pairs sorted by name.
 
136
    Optionally, only return members that satisfy a given predicate."""
 
137
    results = []
 
138
    for key in dir(object):
 
139
        value = getattr(object, key)
 
140
        if not predicate or predicate(value):
 
141
            results.append((key, value))
 
142
    results.sort()
 
143
    return results
 
144
 
 
145
# -------------------------------------------------- source code extraction
 
146
def indentsize(line):
 
147
    """Return the indent size, in spaces, at the start of a line of text."""
 
148
    expline = string.expandtabs(line)
 
149
    return len(expline) - len(string.lstrip(expline))
 
150
 
 
151
def getdoc(object):
 
152
    """Get the documentation string for an object.
 
153
 
 
154
    All tabs are expanded to spaces.  To clean up docstrings that are
 
155
    indented to line up with blocks of code, any whitespace than can be
 
156
    uniformly removed from the second line onwards is removed."""
 
157
    if hasattr(object, '__doc__') and object.__doc__:
 
158
        lines = string.split(string.expandtabs(object.__doc__), '\n')
 
159
        margin = None
 
160
        for line in lines[1:]:
 
161
            content = len(string.lstrip(line))
 
162
            if not content: continue
 
163
            indent = len(line) - content
 
164
            if margin is None: margin = indent
 
165
            else: margin = min(margin, indent)
 
166
        if margin is not None:
 
167
            for i in range(1, len(lines)): lines[i] = lines[i][margin:]
 
168
        return string.join(lines, '\n')
 
169
 
 
170
def getfile(object):
 
171
    """Try to guess which (text or binary) file an object was defined in."""
 
172
    if ismodule(object):
 
173
        if hasattr(object, '__file__'):
 
174
            return object.__file__
 
175
        raise TypeError, 'arg is a built-in module'
 
176
    if isclass(object):
 
177
        object = sys.modules[object.__module__]
 
178
        if hasattr(object, '__file__'):
 
179
            return object.__file__
 
180
        raise TypeError, 'arg is a built-in class'
 
181
    if ismethod(object):
 
182
        object = object.im_func
 
183
    if isfunction(object):
 
184
        object = object.func_code
 
185
    if istraceback(object):
 
186
        object = object.tb_frame
 
187
    if isframe(object):
 
188
        object = object.f_code
 
189
    if iscode(object):
 
190
        return object.co_filename
 
191
    raise TypeError, 'arg is not a module, class, method, ' \
 
192
                     'function, traceback, frame, or code object'
 
193
 
 
194
modulesbyfile = {}
 
195
 
 
196
def getmodule(object):
 
197
    """Try to guess which module an object was defined in."""
 
198
    if isclass(object):
 
199
        return sys.modules[object.__module__]
 
200
    try:
 
201
        file = getsourcefile(object)
 
202
    except TypeError:
 
203
        return None
 
204
    if modulesbyfile.has_key(file):
 
205
        return sys.modules[modulesbyfile[file]]
 
206
    for module in sys.modules.values():
 
207
        if hasattr(module, '__file__'):
 
208
            modulesbyfile[getsourcefile(module)] = module.__name__
 
209
    if modulesbyfile.has_key(file):
 
210
        return sys.modules[modulesbyfile[file]]
 
211
    main = sys.modules['__main__']
 
212
    try:
 
213
        mainobject = getattr(main, object.__name__)
 
214
        if mainobject is object: return main
 
215
    except AttributeError: pass
 
216
    builtin = sys.modules['__builtin__']
 
217
    try:
 
218
        builtinobject = getattr(builtin, object.__name__)
 
219
        if builtinobject is object: return builtin
 
220
    except AttributeError: pass
 
221
 
 
222
def getsourcefile(object):
 
223
    """Try to guess which Python source file an object was defined in."""
 
224
    filename = getfile(object)
 
225
    if filename[-4:] == '.pyc':
 
226
        filename = filename[:-4] + '.py'
 
227
    return filename
 
228
 
 
229
def findsource(object):
 
230
    """Return the entire source file and starting line number for an object.
 
231
 
 
232
    The argument may be a module, class, method, function, traceback, frame,
 
233
    or code object.  The source code is returned as a list of all the lines
 
234
    in the file and the line number indexes a line in that list.  An IOError
 
235
    is raised if the source code cannot be retrieved."""
 
236
    try:
 
237
        file = open(getsourcefile(object))
 
238
        lines = file.readlines()
 
239
        file.close()
 
240
    except (TypeError, IOError):
 
241
        raise IOError, 'could not get source code'
 
242
 
 
243
    if ismodule(object):
 
244
        return lines, 0
 
245
 
 
246
    if isclass(object):
 
247
        name = object.__name__
 
248
        matches = (['class', name], ['class', name + ':'])
 
249
        for i in range(len(lines)):
 
250
            if string.split(lines[i])[:2] in matches:
 
251
                return lines, i
 
252
        else: raise IOError, 'could not find class definition'
 
253
 
 
254
    if ismethod(object):
 
255
        object = object.im_func
 
256
    if isfunction(object):
 
257
        object = object.func_code
 
258
    if istraceback(object):
 
259
        object = object.tb_frame
 
260
    if isframe(object):
 
261
        object = object.f_code
 
262
    if iscode(object):
 
263
        try:
 
264
            lnum = object.co_firstlineno - 1
 
265
        except AttributeError:
 
266
            raise IOError, 'could not find function definition'
 
267
        else:
 
268
            while lnum > 0:
 
269
                if string.split(lines[lnum])[:1] == ['def']: break
 
270
                lnum = lnum - 1
 
271
            return lines, lnum
 
272
 
 
273
def getcomments(object):
 
274
    """Get lines of comments immediately preceding an object's source code."""
 
275
    try: lines, lnum = findsource(object)
 
276
    except: return None
 
277
 
 
278
    if ismodule(object):
 
279
        # Look for a comment block at the top of the file.
 
280
        start = 0
 
281
        if lines[0][:2] == '#!': start = 1
 
282
        while start < len(lines) and string.strip(lines[start]) in ['', '#']:
 
283
            start = start + 1
 
284
        if lines[start][:1] == '#':
 
285
            comments = []
 
286
            end = start
 
287
            while end < len(lines) and lines[end][:1] == '#':
 
288
                comments.append(string.expandtabs(lines[end]))
 
289
                end = end + 1
 
290
            return string.join(comments, '')
 
291
 
 
292
    # Look for a preceding block of comments at the same indentation.
 
293
    elif lnum > 0:
 
294
        indent = indentsize(lines[lnum])
 
295
        end = lnum - 1
 
296
        if end >= 0 and string.lstrip(lines[end])[:1] == '#' and \
 
297
            indentsize(lines[end]) == indent:
 
298
            comments = [string.lstrip(string.expandtabs(lines[end]))]
 
299
            if end > 0:
 
300
                end = end - 1
 
301
                comment = string.lstrip(string.expandtabs(lines[end]))
 
302
                while comment[:1] == '#' and indentsize(lines[end]) == indent:
 
303
                    comments[:0] = [comment]
 
304
                    end = end - 1
 
305
                    if end < 0: break
 
306
                    comment = string.lstrip(string.expandtabs(lines[end]))
 
307
            while comments and string.strip(comments[0]) == '#':
 
308
                comments[:1] = []
 
309
            while comments and string.strip(comments[-1]) == '#':
 
310
                comments[-1:] = []
 
311
            return string.join(comments, '')
 
312
 
 
313
class ListReader:
 
314
    """Provide a readline() method to return lines from a list of strings."""
 
315
    def __init__(self, lines):
 
316
        self.lines = lines
 
317
        self.index = 0
 
318
 
 
319
    def readline(self):
 
320
        i = self.index
 
321
        if i < len(self.lines):
 
322
            self.index = i + 1
 
323
            return self.lines[i]
 
324
        else: return ''
 
325
 
 
326
class EndOfBlock(Exception): pass
 
327
 
 
328
class BlockFinder:
 
329
    """Provide a tokeneater() method to detect the end of a code block."""
 
330
    def __init__(self):
 
331
        self.indent = 0
 
332
        self.started = 0
 
333
        self.last = 0
 
334
 
 
335
    def tokeneater(self, type, token, (srow, scol), (erow, ecol), line):
 
336
        if not self.started:
 
337
            if type == tokenize.NAME: self.started = 1
 
338
        elif type == tokenize.NEWLINE:
 
339
            self.last = srow
 
340
        elif type == tokenize.INDENT:
 
341
            self.indent = self.indent + 1
 
342
        elif type == tokenize.DEDENT:
 
343
            self.indent = self.indent - 1
 
344
            if self.indent == 0: raise EndOfBlock, self.last
 
345
 
 
346
def getblock(lines):
 
347
    """Extract the block of code at the top of the given list of lines."""
 
348
    try:
 
349
        tokenize.tokenize(ListReader(lines).readline, BlockFinder().tokeneater)
 
350
    except EndOfBlock, eob:
 
351
        return lines[:eob.args[0]]
 
352
 
 
353
def getsourcelines(object):
 
354
    """Return a list of source lines and starting line number for an object.
 
355
 
 
356
    The argument may be a module, class, method, function, traceback, frame,
 
357
    or code object.  The source code is returned as a list of the lines
 
358
    corresponding to the object and the line number indicates where in the
 
359
    original source file the first line of code was found.  An IOError is
 
360
    raised if the source code cannot be retrieved."""
 
361
    lines, lnum = findsource(object)
 
362
 
 
363
    if ismodule(object): return lines, 0
 
364
    else: return getblock(lines[lnum:]), lnum + 1
 
365
 
 
366
def getsource(object):
 
367
    """Return the text of the source code for an object.
 
368
 
 
369
    The argument may be a module, class, method, function, traceback, frame,
 
370
    or code object.  The source code is returned as a single string.  An
 
371
    IOError is raised if the source code cannot be retrieved."""
 
372
    lines, lnum = getsourcelines(object)
 
373
    return string.join(lines, '')
 
374
 
 
375
# --------------------------------------------------- class tree extraction
 
376
def walktree(classes, children, parent):
 
377
    """Recursive helper function for getclasstree()."""
 
378
    results = []
 
379
    classes.sort(lambda a, b: cmp(a.__name__, b.__name__))
 
380
    for c in classes:
 
381
        results.append((c, c.__bases__))
 
382
        if children.has_key(c):
 
383
            results.append(walktree(children[c], children, c))
 
384
    return results
 
385
 
 
386
def getclasstree(classes, unique=0):
 
387
    """Arrange the given list of classes into a hierarchy of nested lists.
 
388
 
 
389
    Where a nested list appears, it contains classes derived from the class
 
390
    whose entry immediately precedes the list.  Each entry is a 2-tuple
 
391
    containing a class and a tuple of its base classes.  If the 'unique'
 
392
    argument is true, exactly one entry appears in the returned structure
 
393
    for each class in the given list.  Otherwise, classes using multiple
 
394
    inheritance and their descendants will appear multiple times."""
 
395
    children = {}
 
396
    roots = []
 
397
    for c in classes:
 
398
        if c.__bases__:
 
399
            for parent in c.__bases__:
 
400
                if not children.has_key(parent):
 
401
                    children[parent] = []
 
402
                children[parent].append(c)
 
403
                if unique and parent in classes: break
 
404
        elif c not in roots:
 
405
            roots.append(c)
 
406
    for parent in children.keys():
 
407
        if parent not in classes:
 
408
            roots.append(parent)
 
409
    return walktree(roots, children, None)
 
410
 
 
411
# ------------------------------------------------ argument list extraction
 
412
# These constants are from Python's compile.h.
 
413
CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 1, 2, 4, 8
 
414
 
 
415
def getargs(co):
 
416
    """Get information about the arguments accepted by a code object.
 
417
 
 
418
    Three things are returned: (args, varargs, varkw), where 'args' is
 
419
    a list of argument names (possibly containing nested lists), and
 
420
    'varargs' and 'varkw' are the names of the * and ** arguments or None."""
 
421
    if not iscode(co): raise TypeError, 'arg is not a code object'
 
422
 
 
423
    code = co.co_code
 
424
    nargs = co.co_argcount
 
425
    names = co.co_varnames
 
426
    args = list(names[:nargs])
 
427
    step = 0
 
428
 
 
429
    # The following acrobatics are for anonymous (tuple) arguments.
 
430
    for i in range(nargs):
 
431
        if args[i][:1] in ['', '.']:
 
432
            stack, remain, count = [], [], []
 
433
            while step < len(code):
 
434
                op = ord(code[step])
 
435
                step = step + 1
 
436
                if op >= dis.HAVE_ARGUMENT:
 
437
                    opname = dis.opname[op]
 
438
                    value = ord(code[step]) + ord(code[step+1])*256
 
439
                    step = step + 2
 
440
                    if opname in ['UNPACK_TUPLE', 'UNPACK_SEQUENCE']:
 
441
                        remain.append(value)
 
442
                        count.append(value)
 
443
                    elif opname == 'STORE_FAST':
 
444
                        stack.append(names[value])
 
445
                        remain[-1] = remain[-1] - 1
 
446
                        while remain[-1] == 0:
 
447
                            remain.pop()
 
448
                            size = count.pop()
 
449
                            stack[-size:] = [stack[-size:]]
 
450
                            if not remain: break
 
451
                            remain[-1] = remain[-1] - 1
 
452
                        if not remain: break
 
453
            args[i] = stack[0]
 
454
 
 
455
    varargs = None
 
456
    if co.co_flags & CO_VARARGS:
 
457
        varargs = co.co_varnames[nargs]
 
458
        nargs = nargs + 1
 
459
    varkw = None
 
460
    if co.co_flags & CO_VARKEYWORDS:
 
461
        varkw = co.co_varnames[nargs]
 
462
    return args, varargs, varkw
 
463
 
 
464
def getargspec(func):
 
465
    """Get the names and default values of a function's arguments.
 
466
 
 
467
    A tuple of four things is returned: (args, varargs, varkw, defaults).
 
468
    'args' is a list of the argument names (it may contain nested lists).
 
469
    'varargs' and 'varkw' are the names of the * and ** arguments or None.
 
470
    'defaults' is an n-tuple of the default values of the last n arguments."""
 
471
    if not isfunction(func): raise TypeError, 'arg is not a Python function'
 
472
    args, varargs, varkw = getargs(func.func_code)
 
473
    return args, varargs, varkw, func.func_defaults
 
474
 
 
475
def getargvalues(frame):
 
476
    """Get information about arguments passed into a particular frame.
 
477
 
 
478
    A tuple of four things is returned: (args, varargs, varkw, locals).
 
479
    'args' is a list of the argument names (it may contain nested lists).
 
480
    'varargs' and 'varkw' are the names of the * and ** arguments or None.
 
481
    'locals' is the locals dictionary of the given frame."""
 
482
    args, varargs, varkw = getargs(frame.f_code)
 
483
    return args, varargs, varkw, frame.f_locals
 
484
 
 
485
def joinseq(seq):
 
486
    if len(seq) == 1:
 
487
        return '(' + seq[0] + ',)'
 
488
    else:
 
489
        return '(' + string.join(seq, ', ') + ')'
 
490
 
 
491
def strseq(object, convert, join=joinseq):
 
492
    """Recursively walk a sequence, stringifying each element."""
 
493
    if type(object) in [types.ListType, types.TupleType]:
 
494
        return join(map(lambda o, c=convert, j=join: strseq(o, c, j), object))
 
495
    else:
 
496
        return convert(object)
 
497
 
 
498
def formatargspec(args, varargs=None, varkw=None, defaults=None,
 
499
                  formatarg=str,
 
500
                  formatvarargs=lambda name: '*' + name,
 
501
                  formatvarkw=lambda name: '**' + name,
 
502
                  formatvalue=lambda value: '=' + repr(value),
 
503
                  join=joinseq):
 
504
    """Format an argument spec from the 4 values returned by getargspec.
 
505
 
 
506
    The first four arguments are (args, varargs, varkw, defaults).  The
 
507
    other four arguments are the corresponding optional formatting functions
 
508
    that are called to turn names and values into strings.  The ninth
 
509
    argument is an optional function to format the sequence of arguments."""
 
510
    specs = []
 
511
    if defaults:
 
512
        firstdefault = len(args) - len(defaults)
 
513
    for i in range(len(args)):
 
514
        spec = strseq(args[i], formatarg, join)
 
515
        if defaults and i >= firstdefault:
 
516
            spec = spec + formatvalue(defaults[i - firstdefault])
 
517
        specs.append(spec)
 
518
    if varargs:
 
519
        specs.append(formatvarargs(varargs))
 
520
    if varkw:
 
521
        specs.append(formatvarkw(varkw))
 
522
    return '(' + string.join(specs, ', ') + ')'
 
523
 
 
524
def formatargvalues(args, varargs, varkw, locals,
 
525
                    formatarg=str,
 
526
                    formatvarargs=lambda name: '*' + name,
 
527
                    formatvarkw=lambda name: '**' + name,
 
528
                    formatvalue=lambda value: '=' + repr(value),
 
529
                    join=joinseq):
 
530
    """Format an argument spec from the 4 values returned by getargvalues.
 
531
 
 
532
    The first four arguments are (args, varargs, varkw, locals).  The
 
533
    next four arguments are the corresponding optional formatting functions
 
534
    that are called to turn names and values into strings.  The ninth
 
535
    argument is an optional function to format the sequence of arguments."""
 
536
    def convert(name, locals=locals,
 
537
                formatarg=formatarg, formatvalue=formatvalue):
 
538
        return formatarg(name) + formatvalue(locals[name])
 
539
    specs = []
 
540
    for i in range(len(args)):
 
541
        specs.append(strseq(args[i], convert, join))
 
542
    if varargs:
 
543
        specs.append(formatvarargs(varargs) + formatvalue(locals[varargs]))
 
544
    if varkw:
 
545
        specs.append(formatvarkw(varkw) + formatvalue(locals[varkw]))
 
546
    return '(' + string.join(specs, ', ') + ')'
 
547
 
 
548
# -------------------------------------------------- stack frame extraction
 
549
def getframeinfo(frame, context=1):
 
550
    """Get information about a frame or traceback object.
 
551
 
 
552
    A tuple of five things is returned: the filename, the line number of
 
553
    the current line, the function name, a list of lines of context from
 
554
    the source code, and the index of the current line within that list.
 
555
    The optional second argument specifies the number of lines of context
 
556
    to return, which are centered around the current line."""
 
557
    if istraceback(frame):
 
558
        frame = frame.tb_frame
 
559
    if not isframe(frame):
 
560
        raise TypeError, 'arg is not a frame or traceback object'
 
561
 
 
562
    filename = getsourcefile(frame)
 
563
    if context > 0:
 
564
        start = frame.f_lineno - 1 - context/2
 
565
        try:
 
566
            lines, lnum = findsource(frame)
 
567
            start = max(start, 1)
 
568
            start = min(start, len(lines) - context)
 
569
            lines = lines[start:start+context]
 
570
            index = frame.f_lineno - 1 - start
 
571
        except:
 
572
            lines = index = None
 
573
    else:
 
574
        lines = index = None
 
575
 
 
576
    return (filename, frame.f_lineno, frame.f_code.co_name, lines, index)
 
577
 
 
578
def getouterframes(frame, context=1):
 
579
    """Get a list of records for a frame and all higher (calling) frames.
 
580
 
 
581
    Each record contains a frame object, filename, line number, function
 
582
    name, a list of lines of context, and index within the context."""
 
583
    framelist = []
 
584
    while frame:
 
585
        framelist.append((frame,) + getframeinfo(frame, context))
 
586
        frame = frame.f_back
 
587
    return framelist
 
588
 
 
589
def getinnerframes(tb, context=1):
 
590
    """Get a list of records for a traceback's frame and all lower frames.
 
591
 
 
592
    Each record contains a frame object, filename, line number, function
 
593
    name, a list of lines of context, and index within the context."""
 
594
    tb = tb.tb_next
 
595
    framelist = []
 
596
    while tb:
 
597
        framelist.append((tb.tb_frame,) + getframeinfo(tb, context))
 
598
        tb = tb.tb_next
 
599
    return framelist
 
600
 
 
601
def currentframe():
 
602
    """Return the frame object for the caller's stack frame."""
 
603
    try:
 
604
        raise 'catch me'
 
605
    except:
 
606
        return sys.exc_traceback.tb_frame.f_back
 
607
 
 
608
if hasattr(sys, '_getframe'): currentframe = sys._getframe
 
609
 
 
610
def stack(context=1):
 
611
    """Return a list of records for the stack above the caller's frame."""
 
612
    return getouterframes(currentframe().f_back, context)
 
613
 
 
614
def trace(context=1):
 
615
    """Return a list of records for the stack below the current exception.""" 
 
616
    return getinnerframes(sys.exc_traceback, context)