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