summaryrefslogtreecommitdiff
path: root/python/helpers/pydev/pydevd_referrers.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/helpers/pydev/pydevd_referrers.py')
-rw-r--r--python/helpers/pydev/pydevd_referrers.py238
1 files changed, 238 insertions, 0 deletions
diff --git a/python/helpers/pydev/pydevd_referrers.py b/python/helpers/pydev/pydevd_referrers.py
new file mode 100644
index 000000000000..66b1a0ef1df4
--- /dev/null
+++ b/python/helpers/pydev/pydevd_referrers.py
@@ -0,0 +1,238 @@
+from pydevd_constants import DictContains
+import sys
+import pydevd_vars
+from os.path import basename
+import traceback
+try:
+ from urllib import quote, quote_plus, unquote, unquote_plus
+except:
+ from urllib.parse import quote, quote_plus, unquote, unquote_plus #@Reimport @UnresolvedImport
+
+#===================================================================================================
+# print_var_node
+#===================================================================================================
+def print_var_node(xml_node, stream):
+ name = xml_node.getAttribute('name')
+ value = xml_node.getAttribute('value')
+ val_type = xml_node.getAttribute('type')
+
+ found_as = xml_node.getAttribute('found_as')
+ stream.write('Name: ')
+ stream.write(unquote_plus(name))
+ stream.write(', Value: ')
+ stream.write(unquote_plus(value))
+ stream.write(', Type: ')
+ stream.write(unquote_plus(val_type))
+ if found_as:
+ stream.write(', Found as: %s' % (unquote_plus(found_as),))
+ stream.write('\n')
+
+#===================================================================================================
+# print_referrers
+#===================================================================================================
+def print_referrers(obj, stream=None):
+ if stream is None:
+ stream = sys.stdout
+ result = get_referrer_info(obj)
+ from xml.dom.minidom import parseString
+ dom = parseString(result)
+
+ xml = dom.getElementsByTagName('xml')[0]
+ for node in xml.childNodes:
+ if node.nodeType == node.TEXT_NODE:
+ continue
+
+ if node.localName == 'for':
+ stream.write('Searching references for: ')
+ for child in node.childNodes:
+ if child.nodeType == node.TEXT_NODE:
+ continue
+ print_var_node(child, stream)
+
+ elif node.localName == 'var':
+ stream.write('Referrer found: ')
+ print_var_node(node, stream)
+
+ else:
+ sys.stderr.write('Unhandled node: %s\n' % (node,))
+
+ return result
+
+
+#===================================================================================================
+# get_referrer_info
+#===================================================================================================
+def get_referrer_info(searched_obj):
+ DEBUG = 0
+ if DEBUG:
+ sys.stderr.write('Getting referrers info.\n')
+ try:
+ try:
+ if searched_obj is None:
+ ret = ['<xml>\n']
+
+ ret.append('<for>\n')
+ ret.append(pydevd_vars.varToXML(
+ searched_obj,
+ 'Skipping getting referrers for None',
+ additionalInXml=' id="%s"' % (id(searched_obj),)))
+ ret.append('</for>\n')
+ ret.append('</xml>')
+ ret = ''.join(ret)
+ return ret
+
+ obj_id = id(searched_obj)
+
+ try:
+ if DEBUG:
+ sys.stderr.write('Getting referrers...\n')
+ import gc
+ referrers = gc.get_referrers(searched_obj)
+ except:
+ traceback.print_exc()
+ ret = ['<xml>\n']
+
+ ret.append('<for>\n')
+ ret.append(pydevd_vars.varToXML(
+ searched_obj,
+ 'Exception raised while trying to get_referrers.',
+ additionalInXml=' id="%s"' % (id(searched_obj),)))
+ ret.append('</for>\n')
+ ret.append('</xml>')
+ ret = ''.join(ret)
+ return ret
+
+ if DEBUG:
+ sys.stderr.write('Found %s referrers.\n' % (len(referrers),))
+
+ curr_frame = sys._getframe()
+ frame_type = type(curr_frame)
+
+ #Ignore this frame and any caller frame of this frame
+
+ ignore_frames = {} #Should be a set, but it's not available on all python versions.
+ while curr_frame is not None:
+ if basename(curr_frame.f_code.co_filename).startswith('pydev'):
+ ignore_frames[curr_frame] = 1
+ curr_frame = curr_frame.f_back
+
+
+ ret = ['<xml>\n']
+
+ ret.append('<for>\n')
+ if DEBUG:
+ sys.stderr.write('Searching Referrers of obj with id="%s"\n' % (obj_id,))
+
+ ret.append(pydevd_vars.varToXML(
+ searched_obj,
+ 'Referrers of obj with id="%s"' % (obj_id,)))
+ ret.append('</for>\n')
+
+ all_objects = None
+
+ for r in referrers:
+ try:
+ if DictContains(ignore_frames, r):
+ continue #Skip the references we may add ourselves
+ except:
+ pass #Ok: unhashable type checked...
+
+ if r is referrers:
+ continue
+
+ r_type = type(r)
+ r_id = str(id(r))
+
+ representation = str(r_type)
+
+ found_as = ''
+ if r_type == frame_type:
+ if DEBUG:
+ sys.stderr.write('Found frame referrer: %r\n' % (r,))
+ for key, val in r.f_locals.items():
+ if val is searched_obj:
+ found_as = key
+ break
+
+ elif r_type == dict:
+ if DEBUG:
+ sys.stderr.write('Found dict referrer: %r\n' % (r,))
+
+ # Try to check if it's a value in the dict (and under which key it was found)
+ for key, val in r.items():
+ if val is searched_obj:
+ found_as = key
+ if DEBUG:
+ sys.stderr.write(' Found as %r in dict\n' % (found_as,))
+ break
+
+ #Ok, there's one annoying thing: many times we find it in a dict from an instance,
+ #but with this we don't directly have the class, only the dict, so, to workaround that
+ #we iterate over all reachable objects ad check if one of those has the given dict.
+ if all_objects is None:
+ all_objects = gc.get_objects()
+
+ for x in all_objects:
+ try:
+ if getattr(x, '__dict__', None) is r:
+ r = x
+ r_type = type(x)
+ r_id = str(id(r))
+ representation = str(r_type)
+ break
+ except:
+ pass #Just ignore any error here (i.e.: ReferenceError, etc.)
+
+ elif r_type in (tuple, list):
+ if DEBUG:
+ sys.stderr.write('Found tuple referrer: %r\n' % (r,))
+
+ #Don't use enumerate() because not all Python versions have it.
+ i = 0
+ for x in r:
+ if x is searched_obj:
+ found_as = '%s[%s]' % (r_type.__name__, i)
+ if DEBUG:
+ sys.stderr.write(' Found as %s in tuple: \n' % (found_as,))
+ break
+ i += 1
+
+ if found_as:
+ found_as = ' found_as="%s"' % (pydevd_vars.makeValidXmlValue(found_as),)
+
+ ret.append(pydevd_vars.varToXML(
+ r,
+ representation,
+ additionalInXml=' id="%s"%s' % (r_id, found_as)))
+ finally:
+ if DEBUG:
+ sys.stderr.write('Done searching for references.\n')
+
+ #If we have any exceptions, don't keep dangling references from this frame to any of our objects.
+ all_objects = None
+ referrers = None
+ searched_obj = None
+ r = None
+ x = None
+ key = None
+ val = None
+ curr_frame = None
+ ignore_frames = None
+ except:
+ traceback.print_exc()
+ ret = ['<xml>\n']
+
+ ret.append('<for>\n')
+ ret.append(pydevd_vars.varToXML(
+ searched_obj,
+ 'Error getting referrers for:',
+ additionalInXml=' id="%s"' % (id(searched_obj),)))
+ ret.append('</for>\n')
+ ret.append('</xml>')
+ ret = ''.join(ret)
+ return ret
+
+ ret.append('</xml>')
+ ret = ''.join(ret)
+ return ret
+