|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2015 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing utilities functions for the debug client. |
|
8 """ |
|
9 |
|
10 # |
|
11 # Taken from inspect.py of Python 3.4 |
|
12 # |
|
13 |
|
14 from collections import namedtuple |
|
15 from inspect import iscode, isframe |
|
16 |
|
17 # Create constants for the compiler flags in Include/code.h |
|
18 # We try to get them from dis to avoid duplication, but fall |
|
19 # back to hardcoding so the dependency is optional |
|
20 try: |
|
21 from dis import COMPILER_FLAG_NAMES |
|
22 except ImportError: |
|
23 CO_OPTIMIZED, CO_NEWLOCALS = 0x1, 0x2 |
|
24 CO_VARARGS, CO_VARKEYWORDS = 0x4, 0x8 |
|
25 CO_NESTED, CO_GENERATOR, CO_NOFREE = 0x10, 0x20, 0x40 |
|
26 else: |
|
27 mod_dict = globals() |
|
28 for k, v in COMPILER_FLAG_NAMES.items(): |
|
29 mod_dict["CO_" + v] = k |
|
30 |
|
31 ArgInfo = namedtuple('ArgInfo', 'args varargs keywords locals') |
|
32 |
|
33 |
|
34 def getargvalues(frame): |
|
35 """ |
|
36 Function to get information about arguments passed into a |
|
37 particular frame. |
|
38 |
|
39 @param frame reference to a frame object to be processed |
|
40 @type frame |
|
41 @return tuple of four things, where 'args' is a list of the argument names, |
|
42 'varargs' and 'varkw' are the names of the * and ** arguments or None |
|
43 and 'locals' is the locals dictionary of the given frame. |
|
44 @exception TypeError raised if the input parameter is not a frame object |
|
45 """ |
|
46 if not isframe(frame): |
|
47 raise TypeError('{!r} is not a frame object'.format(frame)) |
|
48 |
|
49 args, varargs, kwonlyargs, varkw = _getfullargs(frame.f_code) |
|
50 return ArgInfo(args + kwonlyargs, varargs, varkw, frame.f_locals) |
|
51 |
|
52 |
|
53 def _getfullargs(co): |
|
54 """ |
|
55 Protected function to get information about the arguments accepted |
|
56 by a code object. |
|
57 |
|
58 @param co reference to a code object to be processed |
|
59 @type code |
|
60 @return tuple of four things, where 'args' and 'kwonlyargs' are lists of |
|
61 argument names, and 'varargs' and 'varkw' are the names of the |
|
62 * and ** arguments or None. |
|
63 @exception TypeError raised if the input parameter is not a code object |
|
64 """ |
|
65 if not iscode(co): |
|
66 raise TypeError('{!r} is not a code object'.format(co)) |
|
67 |
|
68 nargs = co.co_argcount |
|
69 names = co.co_varnames |
|
70 nkwargs = co.co_kwonlyargcount |
|
71 args = list(names[:nargs]) |
|
72 kwonlyargs = list(names[nargs:nargs + nkwargs]) |
|
73 |
|
74 nargs += nkwargs |
|
75 varargs = None |
|
76 if co.co_flags & CO_VARARGS: |
|
77 varargs = co.co_varnames[nargs] |
|
78 nargs = nargs + 1 |
|
79 varkw = None |
|
80 if co.co_flags & CO_VARKEYWORDS: |
|
81 varkw = co.co_varnames[nargs] |
|
82 return args, varargs, kwonlyargs, varkw |
|
83 |
|
84 |
|
85 def formatargvalues(args, varargs, varkw, locals, |
|
86 formatarg=str, |
|
87 formatvarargs=lambda name: '*' + name, |
|
88 formatvarkw=lambda name: '**' + name, |
|
89 formatvalue=lambda value: '=' + repr(value)): |
|
90 """ |
|
91 Function to format an argument spec from the 4 values returned |
|
92 by getargvalues. |
|
93 |
|
94 @param args list of argument names |
|
95 @type list of str |
|
96 @param varargs name of the variable arguments |
|
97 @type str |
|
98 @param varkw name of the keyword arguments |
|
99 @type str |
|
100 @param locals reference to the local variables dictionary |
|
101 @type dict |
|
102 @keyparam formatarg argument formatting function |
|
103 @type func |
|
104 @keyparam formatvarargs variable arguments formatting function |
|
105 @type func |
|
106 @keyparam formatvarkw keyword arguments formatting function |
|
107 @type func |
|
108 @keyparam formatvalue value formating functtion |
|
109 @type func |
|
110 @return formatted call signature |
|
111 @rtype str |
|
112 """ |
|
113 specs = [] |
|
114 for i in range(len(args)): |
|
115 name = args[i] |
|
116 specs.append(formatarg(name) + formatvalue(locals[name])) |
|
117 if varargs: |
|
118 specs.append(formatvarargs(varargs) + formatvalue(locals[varargs])) |
|
119 if varkw: |
|
120 specs.append(formatvarkw(varkw) + formatvalue(locals[varkw])) |
|
121 argvalues = '(' + ', '.join(specs) + ')' |
|
122 if '__return__' in locals: |
|
123 argvalues += " -> " + formatvalue(locals['__return__']) |
|
124 return argvalues |