Snapshot idea/138.1696 from git://git.jetbrains.org/idea/community.git

Change-Id: I50c97b83a815ce635e49a38380ba5b8765e4b16a
diff --git a/python/helpers/pydev/pydevd_traceproperty.py b/python/helpers/pydev/pydevd_traceproperty.py
new file mode 100644
index 0000000..d8e7e5f
--- /dev/null
+++ b/python/helpers/pydev/pydevd_traceproperty.py
@@ -0,0 +1,108 @@
+'''For debug purpose we are replacing actual builtin property by the debug property
+'''
+from pydevd_comm import GetGlobalDebugger
+from pydevd_constants import * #@UnusedWildImport
+import pydevd_tracing
+
+#=======================================================================================================================
+# replace_builtin_property
+#=======================================================================================================================
+def replace_builtin_property(new_property=None):
+    if new_property is None:
+        new_property = DebugProperty
+    original = property
+    if not IS_PY3K:
+        try:
+            import __builtin__
+            __builtin__.__dict__['property'] = new_property
+        except:
+            if DebugInfoHolder.DEBUG_TRACE_LEVEL:
+                import traceback;traceback.print_exc() #@Reimport
+    else:
+        try:
+            import builtins #Python 3.0 does not have the __builtin__ module @UnresolvedImport
+            builtins.__dict__['property'] = new_property
+        except:
+            if DebugInfoHolder.DEBUG_TRACE_LEVEL:
+                import traceback;traceback.print_exc() #@Reimport
+    return original
+
+
+#=======================================================================================================================
+# DebugProperty
+#=======================================================================================================================
+class DebugProperty(object):
+    """A custom property which allows python property to get
+    controlled by the debugger and selectively disable/re-enable
+    the tracing.
+    """
+
+
+    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
+        self.fget = fget
+        self.fset = fset
+        self.fdel = fdel
+        self.__doc__ = doc
+
+
+    def __get__(self, obj, objtype=None):
+        if obj is None:
+            return self
+        global_debugger = GetGlobalDebugger()
+        try:
+            if global_debugger is not None and global_debugger.disable_property_getter_trace:
+                pydevd_tracing.SetTrace(None)
+            if self.fget is None:
+                raise AttributeError("unreadable attribute")
+            return self.fget(obj)
+        finally:
+            if global_debugger is not None:
+                pydevd_tracing.SetTrace(global_debugger.trace_dispatch)
+
+
+    def __set__(self, obj, value):
+        global_debugger = GetGlobalDebugger()
+        try:
+            if global_debugger is not None and global_debugger.disable_property_setter_trace:
+                pydevd_tracing.SetTrace(None)
+            if self.fset is None:
+                raise AttributeError("can't set attribute")
+            self.fset(obj, value)
+        finally:
+            if global_debugger is not None:
+                pydevd_tracing.SetTrace(global_debugger.trace_dispatch)
+
+
+    def __delete__(self, obj):
+        global_debugger = GetGlobalDebugger()
+        try:
+            if global_debugger is not None and global_debugger.disable_property_deleter_trace:
+                pydevd_tracing.SetTrace(None)
+            if self.fdel is None:
+                raise AttributeError("can't delete attribute")
+            self.fdel(obj)
+        finally:
+            if global_debugger is not None:
+                pydevd_tracing.SetTrace(global_debugger.trace_dispatch)
+
+
+    def getter(self, fget):
+        """Overriding getter decorator for the property
+        """
+        self.fget = fget
+        return self
+
+
+    def setter(self, fset):
+        """Overriding setter decorator for the property
+        """
+        self.fset = fset
+        return self
+
+
+    def deleter(self, fdel):
+        """Overriding deleter decorator for the property
+        """
+        self.fdel = fdel
+        return self
+