From ff01af6a0ea4e985134dc930d18cf2ae2af54976 2014-01-21 22:13:33
From: Jonathan Frederic <jdfreder@calpoly.edu>
Date: 2014-01-21 22:13:33
Subject: [PATCH] Reorganized attrs in widget.py

---

diff --git a/IPython/html/widgets/widget.py b/IPython/html/widgets/widget.py
index bb4d9d0..b2846de 100644
--- a/IPython/html/widgets/widget.py
+++ b/IPython/html/widgets/widget.py
@@ -26,7 +26,9 @@ from IPython.utils.py3compat import string_types
 #-----------------------------------------------------------------------------
 class Widget(LoggingConfigurable):
 
-    # Shared declarations (Class level)
+    #-------------------------------------------------------------------------
+    # Class attributes
+    #-------------------------------------------------------------------------
     widget_construction_callback = None
     widgets = {}
 
@@ -42,42 +44,18 @@ class Widget(LoggingConfigurable):
         if Widget.widget_construction_callback is not None and callable(Widget.widget_construction_callback):
             Widget.widget_construction_callback(widget)
 
-    # Public declarations (Instance level)
+    #-------------------------------------------------------------------------
+    # Traits
+    #-------------------------------------------------------------------------
     model_name = Unicode('WidgetModel', help="""Name of the backbone model 
         registered in the front-end to create and sync this widget with.""")
     view_name = Unicode(help="""Default view registered in the front-end
         to use to represent the widget.""", sync=True)
-
-    @contextmanager
-    def property_lock(self, key, value):
-        """Lock a property-value pair.
-
-        NOTE: This, in addition to the single lock for all state changes, is 
-        flawed.  In the future we may want to look into buffering state changes 
-        back to the front-end."""
-        self._property_lock = (key, value)
-        try:
-            yield
-        finally:
-            self._property_lock = (None, None)
-
-    def should_send_property(self, key, value):
-        """Check the property lock (property_lock)"""
-        return key != self._property_lock[0] or \
-        value != self._property_lock[1]
-
-    @property
-    def keys(self):
-        if self._keys is None:
-            self._keys = []
-            for trait_name in self.trait_names():
-                if self.trait_metadata(trait_name, 'sync'):
-                    self._keys.append(trait_name)
-        return self._keys
-
-    # Private/protected declarations
     _comm = Instance('IPython.kernel.comm.Comm')
-    
+
+    #-------------------------------------------------------------------------
+    # (Con/de)structor
+    #-------------------------------------------------------------------------    
     def __init__(self, **kwargs):
         """Public constructor"""
         self.closed = False
@@ -94,21 +72,17 @@ class Widget(LoggingConfigurable):
         """Object disposal"""
         self.close()
 
-    def close(self):
-        """Close method.  
-
-        Closes the widget which closes the underlying comm.
-        When the comm is closed, all of the widget views are automatically
-        removed from the front-end."""
-        if not self.closed:
-            self._comm.close() 
-            self._close()
-
-    def _close(self):
-        """Unsafe close"""
-        del Widget.widgets[self.model_id]
-        self._comm = None
-        self.closed = True
+    #-------------------------------------------------------------------------
+    # Properties
+    #-------------------------------------------------------------------------    
+    @property
+    def keys(self):
+        if self._keys is None:
+            self._keys = []
+            for trait_name in self.trait_names():
+                if self.trait_metadata(trait_name, 'sync'):
+                    self._keys.append(trait_name)
+        return self._keys
 
     @property
     def comm(self):
@@ -127,50 +101,19 @@ class Widget(LoggingConfigurable):
     def model_id(self):
         return self.comm.comm_id
 
-    # Event handlers
-    def _handle_msg(self, msg):
-        """Called when a msg is received from the front-end"""
-        data = msg['content']['data']
-        method = data['method']
-        if not method in ['backbone', 'custom']:
-            self.log.error('Unknown front-end to back-end widget msg with method "%s"' % method)
-
-        # Handle backbone sync methods CREATE, PATCH, and UPDATE all in one.
-        if method == 'backbone' and 'sync_data' in data:
-            sync_data = data['sync_data']
-            self._handle_receive_state(sync_data) # handles all methods
-
-        # Handle a custom msg from the front-end
-        elif method == 'custom':
-            if 'custom_content' in data:
-                self._handle_custom_msg(data['custom_content'])
-
-    def _handle_receive_state(self, sync_data):
-        """Called when a state is received from the front-end."""
-        for name in self.keys:
-            if name in sync_data:
-                value = self._unpack_widgets(sync_data[name])
-                with self.property_lock(name, value):
-                    setattr(self, name, value)
-
-    def _handle_custom_msg(self, content):
-        """Called when a custom msg is received."""
-        for handler in self._msg_callbacks:
-            handler(self, content)
-
-    def _handle_property_changed(self, name, old, new):
-        """Called when a property has been changed."""
-        # Make sure this isn't information that the front-end just sent us.
-        if self.should_send_property(name, new):
-            # Send new state to front-end
-            self.send_state(key=name)
+    #-------------------------------------------------------------------------
+    # Methods
+    #-------------------------------------------------------------------------    
+    def close(self):
+        """Close method.  
 
-    def _handle_displayed(self, **kwargs):
-        """Called when a view has been displayed for this widget instance"""
-        for handler in self._display_callbacks:
-            handler(self, **kwargs)
+        Closes the widget which closes the underlying comm.
+        When the comm is closed, all of the widget views are automatically
+        removed from the front-end."""
+        if not self.closed:
+            self._comm.close() 
+            self._close()
 
-    # Public methods
     def send_state(self, key=None):
         """Sends the widget state, or a piece of it, to the front-end.
 
@@ -195,49 +138,6 @@ class Widget(LoggingConfigurable):
         keys = self.keys if key is None else [key]
         return {k: self._pack_widgets(getattr(self, k)) for k in keys} 
 
-    def _pack_widgets(self, values):
-        """Recursively converts all widget instances to model id strings.
-
-        Children widgets will be stored and transmitted to the front-end by 
-        their model ids."""
-        if isinstance(values, dict):
-            new_dict = {}
-            for key, value in values.items():
-                new_dict[key] = self._pack_widgets(value)
-            return new_dict
-        elif isinstance(values, list):
-            new_list = []
-            for value in values:
-                new_list.append(self._pack_widgets(value))
-            return new_list
-        elif isinstance(values, Widget):
-            return values.model_id
-        else:
-            return values
-
-    def _unpack_widgets(self, values):
-        """Recursively converts all model id strings to widget instances.
-
-        Children widgets will be stored and transmitted to the front-end by 
-        their model ids."""
-        if isinstance(values, dict):
-            new_dict = {}
-            for key, values in values.items():
-                new_dict[key] = self._unpack_widgets(values[key])
-            return new_dict
-        elif isinstance(values, list):
-            new_list = []
-            for value in values:
-                new_list.append(self._unpack_widgets(value))
-            return new_list
-        elif isinstance(values, string_types):
-            if values in Widget.widgets:
-                return Widget.widgets[values]
-            else:
-                return values
-        else:
-            return values
-
     def send(self, content):
         """Sends a custom msg to the widget model in the front-end.
 
@@ -300,7 +200,119 @@ class Widget(LoggingConfigurable):
             else:
                 raise Exception('Callback must be callable.')
 
+    #-------------------------------------------------------------------------
     # Support methods
+    #-------------------------------------------------------------------------
+    @contextmanager
+    def _property_lock(self, key, value):
+        """Lock a property-value pair.
+
+        NOTE: This, in addition to the single lock for all state changes, is 
+        flawed.  In the future we may want to look into buffering state changes 
+        back to the front-end."""
+        self._property_lock = (key, value)
+        try:
+            yield
+        finally:
+            self._property_lock = (None, None)
+
+    def _should_send_property(self, key, value):
+        """Check the property lock (property_lock)"""
+        return key != self._property_lock[0] or \
+        value != self._property_lock[1]
+    
+    def _close(self):
+        """Unsafe close"""
+        del Widget.widgets[self.model_id]
+        self._comm = None
+        self.closed = True
+
+    # Event handlers
+    def _handle_msg(self, msg):
+        """Called when a msg is received from the front-end"""
+        data = msg['content']['data']
+        method = data['method']
+        if not method in ['backbone', 'custom']:
+            self.log.error('Unknown front-end to back-end widget msg with method "%s"' % method)
+
+        # Handle backbone sync methods CREATE, PATCH, and UPDATE all in one.
+        if method == 'backbone' and 'sync_data' in data:
+            sync_data = data['sync_data']
+            self._handle_receive_state(sync_data) # handles all methods
+
+        # Handle a custom msg from the front-end
+        elif method == 'custom':
+            if 'custom_content' in data:
+                self._handle_custom_msg(data['custom_content'])
+
+    def _handle_receive_state(self, sync_data):
+        """Called when a state is received from the front-end."""
+        for name in self.keys:
+            if name in sync_data:
+                value = self._unpack_widgets(sync_data[name])
+                with self._property_lock(name, value):
+                    setattr(self, name, value)
+
+    def _handle_custom_msg(self, content):
+        """Called when a custom msg is received."""
+        for handler in self._msg_callbacks:
+            handler(self, content)
+
+    def _handle_property_changed(self, name, old, new):
+        """Called when a property has been changed."""
+        # Make sure this isn't information that the front-end just sent us.
+        if self._should_send_property(name, new):
+            # Send new state to front-end
+            self.send_state(key=name)
+
+    def _handle_displayed(self, **kwargs):
+        """Called when a view has been displayed for this widget instance"""
+        for handler in self._display_callbacks:
+            handler(self, **kwargs)
+
+    def _pack_widgets(self, values):
+        """Recursively converts all widget instances to model id strings.
+
+        Children widgets will be stored and transmitted to the front-end by 
+        their model ids."""
+        if isinstance(values, dict):
+            new_dict = {}
+            for key, value in values.items():
+                new_dict[key] = self._pack_widgets(value)
+            return new_dict
+        elif isinstance(values, list):
+            new_list = []
+            for value in values:
+                new_list.append(self._pack_widgets(value))
+            return new_list
+        elif isinstance(values, Widget):
+            return values.model_id
+        else:
+            return values
+
+    def _unpack_widgets(self, values):
+        """Recursively converts all model id strings to widget instances.
+
+        Children widgets will be stored and transmitted to the front-end by 
+        their model ids."""
+        if isinstance(values, dict):
+            new_dict = {}
+            for key, values in values.items():
+                new_dict[key] = self._unpack_widgets(values[key])
+            return new_dict
+        elif isinstance(values, list):
+            new_list = []
+            for value in values:
+                new_list.append(self._unpack_widgets(value))
+            return new_list
+        elif isinstance(values, string_types):
+            if values in Widget.widgets:
+                return Widget.widgets[values]
+            else:
+                return values
+        else:
+            return values
+
     def _ipython_display_(self, **kwargs):
         """Called when `IPython.display.display` is called on the widget."""
         # Show view.  By sending a display message, the comm is opened and the
@@ -315,8 +327,6 @@ class Widget(LoggingConfigurable):
 
 class DOMWidget(Widget):
     visible = Bool(True, help="Whether or not the widget is visible.", sync=True)
-
-    # Private/protected declarations
     _css = Dict(sync=True) # Internal CSS property dict
 
     def get_css(self, key, selector=""):