blob: 73258e6fcc655cc20b08ec886b800ffee12a642f [file] [log] [blame]
Tor Norbye3a2425a2013-11-04 10:16:08 -08001import pydev_log
2import traceback
3import pydevd_resolver
4from pydevd_constants import * #@UnusedWildImport
5from types import * #@UnusedWildImport
6
7try:
8 from urllib import quote
9except:
10 from urllib.parse import quote #@UnresolvedImport
11
12try:
13 from xml.sax.saxutils import escape
14
15 def makeValidXmlValue(s):
16 return escape(s, {'"': '"'})
17except:
18 #Simple replacement if it's not there.
19 def makeValidXmlValue(s):
20 return s.replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;')
21
22class ExceptionOnEvaluate:
23 def __init__(self, result):
24 self.result = result
25
26#------------------------------------------------------------------------------------------------------ resolvers in map
27
28if not sys.platform.startswith("java"):
29 typeMap = [
30 #None means that it should not be treated as a compound variable
31
32 #isintance does not accept a tuple on some versions of python, so, we must declare it expanded
33 (type(None), None,),
34 (int, None),
35 (float, None),
36 (complex, None),
37 (str, None),
38 (tuple, pydevd_resolver.tupleResolver),
39 (list, pydevd_resolver.tupleResolver),
40 (dict, pydevd_resolver.dictResolver),
41 ]
42
43 try:
44 typeMap.append((long, None))
45 except:
46 pass #not available on all python versions
47
48 try:
49 typeMap.append((unicode, None))
50 except:
51 pass #not available on all python versions
52
53 try:
54 typeMap.append((set, pydevd_resolver.setResolver))
55 except:
56 pass #not available on all python versions
57
58 try:
59 typeMap.append((frozenset, pydevd_resolver.setResolver))
60 except:
61 pass #not available on all python versions
62
63else: #platform is java
64 from org.python import core #@UnresolvedImport
65
66 typeMap = [
67 (core.PyNone, None),
68 (core.PyInteger, None),
69 (core.PyLong, None),
70 (core.PyFloat, None),
71 (core.PyComplex, None),
72 (core.PyString, None),
73 (core.PyTuple, pydevd_resolver.tupleResolver),
74 (core.PyList, pydevd_resolver.tupleResolver),
75 (core.PyDictionary, pydevd_resolver.dictResolver),
76 (core.PyStringMap, pydevd_resolver.dictResolver),
77 ]
78
79 if hasattr(core, 'PyJavaInstance'):
80 #Jython 2.5b3 removed it.
81 typeMap.append((core.PyJavaInstance, pydevd_resolver.instanceResolver))
82
83
84def getType(o):
85 """ returns a triple (typeObject, typeString, resolver
86 resolver != None means that variable is a container,
87 and should be displayed as a hierarchy.
88 Use the resolver to get its attributes.
89
90 All container objects should have a resolver.
91 """
92
93 try:
94 type_object = type(o)
95 type_name = type_object.__name__
96 except:
97 #This happens for org.python.core.InitModule
98 return 'Unable to get Type', 'Unable to get Type', None
99
100 try:
101 if type_name == 'org.python.core.PyJavaInstance':
102 return type_object, type_name, pydevd_resolver.instanceResolver
103
104 if type_name == 'org.python.core.PyArray':
105 return type_object, type_name, pydevd_resolver.jyArrayResolver
106
107 for t in typeMap:
108 if isinstance(o, t[0]):
109 return type_object, type_name, t[1]
110 except:
111 traceback.print_exc()
112
113 #no match return default
114 return type_object, type_name, pydevd_resolver.defaultResolver
115
116def frameVarsToXML(frame_f_locals):
117 """ dumps frame variables to XML
118 <var name="var_name" scope="local" type="type" value="value"/>
119 """
120 xml = ""
121
122 keys = frame_f_locals.keys()
123 if hasattr(keys, 'sort'):
124 keys.sort() #Python 3.0 does not have it
125 else:
126 keys = sorted(keys) #Jython 2.1 does not have it
127
128 for k in keys:
129 try:
130 v = frame_f_locals[k]
131 xml += varToXML(v, str(k))
132 except Exception:
133 traceback.print_exc()
134 pydev_log.error("Unexpected error, recovered safely.\n")
135
136 return xml
137
138
139def varToXML(val, name, doTrim=True):
140 """ single variable or dictionary to xml representation """
141
142 is_exception_on_eval = isinstance(val, ExceptionOnEvaluate)
143
144 if is_exception_on_eval:
145 v = val.result
146 else:
147 v = val
148
149 type, typeName, resolver = getType(v)
150
151 try:
152 if hasattr(v, '__class__'):
153 try:
154 cName = str(v.__class__)
155 if cName.find('.') != -1:
156 cName = cName.split('.')[-1]
157
158 elif cName.find("'") != -1: #does not have '.' (could be something like <type 'int'>)
159 cName = cName[cName.index("'") + 1:]
160
161 if cName.endswith("'>"):
162 cName = cName[:-2]
163 except:
164 cName = str(v.__class__)
165 value = '%s: %s' % (cName, v)
166 else:
167 value = str(v)
168 except:
169 try:
170 value = repr(v)
171 except:
172 value = 'Unable to get repr for %s' % v.__class__
173
174 try:
175 name = quote(name, '/>_= ') #TODO: Fix PY-5834 without using quote
176 except:
177 pass
178 xml = '<var name="%s" type="%s"' % (makeValidXmlValue(name), makeValidXmlValue(typeName))
179
180 if value:
181 #cannot be too big... communication may not handle it.
182 if len(value) > MAXIMUM_VARIABLE_REPRESENTATION_SIZE and doTrim:
183 value = value[0:MAXIMUM_VARIABLE_REPRESENTATION_SIZE]
184 value += '...'
185
186 #fix to work with unicode values
187 try:
188 if not IS_PY3K:
189 if isinstance(value, unicode):
190 value = value.encode('utf-8')
191 else:
192 if isinstance(value, bytes):
193 value = value.encode('utf-8')
194 except TypeError: #in java, unicode is a function
195 pass
196
197 xmlValue = ' value="%s"' % (makeValidXmlValue(quote(value, '/>_= ')))
198 else:
199 xmlValue = ''
200
201 if is_exception_on_eval:
202 xmlCont = ' isErrorOnEval="True"'
203 else:
204 if resolver is not None:
205 xmlCont = ' isContainer="True"'
206 else:
207 xmlCont = ''
208
209 return ''.join((xml, xmlValue, xmlCont, ' />\n'))