[tor-commits] [arm/master] Using @property for GraphPanel attributes

atagar at torproject.org atagar at torproject.org
Tue Nov 18 06:09:38 UTC 2014


commit e773d64a6046ee3f2256b9ba26a078efd52eb4cd
Author: Damian Johnson <atagar at torproject.org>
Date:   Sun Nov 16 12:25:47 2014 -0800

    Using @property for GraphPanel attributes
    
    Neat, learned something new. Nice decorator replaement for the getter/setter
    pattern.
---
 arm/graph_panel.py  |  170 ++++++++++++++++++++++-----------------------------
 arm/menu/actions.py |    8 +--
 arm/util/panel.py   |    2 +-
 3 files changed, 79 insertions(+), 101 deletions(-)

diff --git a/arm/graph_panel.py b/arm/graph_panel.py
index 3dfefbe..b6f8c97 100644
--- a/arm/graph_panel.py
+++ b/arm/graph_panel.py
@@ -355,7 +355,7 @@ class GraphPanel(panel.Panel):
   def __init__(self, stdscr):
     panel.Panel.__init__(self, stdscr, 'graph', 0)
 
-    self._current_display = None if CONFIG['features.graph.type'] == 'none' else CONFIG['features.graph.type']
+    self._displayed_stat = None if CONFIG['features.graph.type'] == 'none' else CONFIG['features.graph.type']
     self._update_interval = CONFIG['features.graph.interval']
     self._bounds = CONFIG['features.graph.bound']
 
@@ -386,13 +386,49 @@ class GraphPanel(panel.Panel):
         else:
           log.notice(msg('panel.graphing.prepopulation_all_successful'))
 
-        self._update_interval = Interval.FIFTEEN_MINUTE
+        self.update_interval = Interval.FIFTEEN_MINUTE
       except ValueError as exc:
         log.info(msg('panel.graphing.prepopulation_failure', error = exc))
 
     controller.add_event_listener(self.bandwidth_event, EventType.BW)
     controller.add_status_listener(self.reset_listener)
 
+  @property
+  def displayed_stat(self):
+    return self._displayed_stat
+
+  @displayed_stat.setter
+  def displayed_stat(self, value):
+    if value is not None and value not in self._stats.keys():
+      raise ValueError("%s isn't a graphed statistic" % value)
+
+    self._displayed_stat = value
+
+  def stat_options(self):
+    return self._stats.keys()
+
+  @property
+  def update_interval(self):
+    return self._update_interval
+
+  @update_interval.setter
+  def update_interval(self, value):
+    if value not in Interval:
+      raise ValueError("%s isn't a valid graphing update interval" % value)
+
+    self._update_interval = value
+
+  @property
+  def bounds_type(self):
+    return self._bounds
+
+  @bounds_type.setter
+  def bounds_type(self, value):
+    if value not in Bounds:
+      raise ValueError("%s isn't a valid type of bounds" % value)
+
+    self._bounds = value
+
   def bandwidth_event(self, event):
     for stat in self._stats.values():
       stat.bandwidth_event(event)
@@ -408,8 +444,8 @@ class GraphPanel(panel.Panel):
 
         arm.controller.get_controller().redraw()
 
-    update_rate = INTERVAL_SECONDS[self._update_interval]
-    param = self.get_attr('_stats')[self._current_display]
+    update_rate = INTERVAL_SECONDS[self.update_interval]
+    param = self.get_attr('_stats')[self.displayed_stat]
 
     if param.primary.tick % update_rate == 0:
       self.redraw(True)
@@ -417,52 +453,17 @@ class GraphPanel(panel.Panel):
   def reset_listener(self, controller, event_type, _):
     self.redraw(True)
 
-  def get_update_interval(self):
-    """
-    Provides the rate that we update the graph at.
-    """
-
-    return self._update_interval
-
-  def set_update_interval(self, update_interval):
-    """
-    Sets the rate that we update the graph at.
-
-    Arguments:
-      update_interval - update time enum
-    """
-
-    self._update_interval = update_interval
-
-  def get_bounds_type(self):
-    """
-    Provides the type of graph bounds used.
-    """
-
-    return self._bounds
-
-  def set_bounds_type(self, bounds_type):
-    """
-    Sets the type of graph boundaries we use.
-
-    Arguments:
-      bounds_type - graph bounds enum
-    """
-
-    self._bounds = bounds_type
-
   def get_height(self):
     """
-    Provides the height requested by the currently displayed GraphCategory
-    (zero if hidden).
+    Provides the height of the content.
     """
 
-    if self._current_display:
-      height = DEFAULT_CONTENT_HEIGHT + self._graph_height
-    else:
-      height = 0
+    if not self.displayed_stat:
+      return 0
+
+    height = DEFAULT_CONTENT_HEIGHT + self._graph_height
 
-    if self._current_display == GraphStat.BANDWIDTH and self._accounting_stats:
+    if self.displayed_stat == GraphStat.BANDWIDTH and self._accounting_stats:
       height += 3
 
     return height
@@ -518,7 +519,7 @@ class GraphPanel(panel.Panel):
       self.resize_graph()
     elif key.match('b'):
       # uses the next boundary type
-      self._bounds = Bounds.next(self._bounds)
+      self.bounds_type = Bounds.next(self.bounds_type)
       self.redraw(True)
     elif key.match('s'):
       # provides a menu to pick the graphed stats
@@ -534,8 +535,8 @@ class GraphPanel(panel.Panel):
         words = label.split()
         options.append(' '.join(word[0].upper() + word[1:] for word in words))
 
-      if self._current_display:
-        initial_selection = available_stats.index(self._current_display) + 1
+      if self.displayed_stat:
+        initial_selection = available_stats.index(self.displayed_stat) + 1
       else:
         initial_selection = 0
 
@@ -544,16 +545,16 @@ class GraphPanel(panel.Panel):
       # applies new setting
 
       if selection == 0:
-        self.set_stats(None)
+        self.displayed_stat = None
       elif selection != -1:
-        self.set_stats(available_stats[selection - 1])
+        self.displayed_stat = available_stats[selection - 1]
     elif key.match('i'):
       # provides menu to pick graph panel update interval
 
-      selection = arm.popups.show_menu('Update Interval:', list(Interval), list(Interval).index(self._update_interval))
+      selection = arm.popups.show_menu('Update Interval:', list(Interval), list(Interval).index(self.update_interval))
 
       if selection != -1:
-        self._update_interval = list(Interval)[selection]
+        self.update_interval = list(Interval)[selection]
     else:
       return False
 
@@ -562,55 +563,55 @@ class GraphPanel(panel.Panel):
   def get_help(self):
     return [
       ('r', 'resize graph', None),
-      ('s', 'graphed stats', self._current_display if self._current_display else 'none'),
-      ('b', 'graph bounds', self._bounds.lower()),
-      ('i', 'graph update interval', self._update_interval),
+      ('s', 'graphed stats', self.displayed_stat if self.displayed_stat else 'none'),
+      ('b', 'graph bounds', self.bounds_type.lower()),
+      ('i', 'graph update interval', self.update_interval),
     ]
 
   def draw(self, width, height):
-    if not self._current_display:
+    if not self.displayed_stat:
       return
 
-    param = self.get_attr('_stats')[self._current_display]
+    param = self.get_attr('_stats')[self.displayed_stat]
     graph_column = min((width - 10) / 2, CONFIG['features.graph.max_width'])
 
     if self.is_title_visible():
-      title = CONFIG['attr.graph.title'].get(self._current_display, '')
+      title = CONFIG['attr.graph.title'].get(self.displayed_stat, '')
       title_stats = str_tools.join(param.title_stats, ', ', width - len(title) - 4)
       title = '%s (%s):' % (title, title_stats) if title_stats else '%s:' % title
       self.addstr(0, 0, title, curses.A_STANDOUT)
 
     # top labels
 
-    primary_header = CONFIG['attr.graph.header.primary'].get(self._current_display, '')
+    primary_header = CONFIG['attr.graph.header.primary'].get(self.displayed_stat, '')
     primary_header_stats = str_tools.join(param.primary_header_stats, '', (width / 2) - len(primary_header) - 4)
     left = '%s (%s):' % (primary_header, primary_header_stats) if primary_header_stats else '%s:' % primary_header
     self.addstr(1, 0, left, curses.A_BOLD, PRIMARY_COLOR)
 
-    secondary_header = CONFIG['attr.graph.header.secondary'].get(self._current_display, '')
+    secondary_header = CONFIG['attr.graph.header.secondary'].get(self.displayed_stat, '')
     secondary_header_stats = str_tools.join(param.secondary_header_stats, '', (width / 2) - len(secondary_header) - 4)
     right = '%s (%s):' % (secondary_header, secondary_header_stats) if secondary_header_stats else '%s:' % secondary_header
     self.addstr(1, graph_column + 5, right, curses.A_BOLD, SECONDARY_COLOR)
 
     # determines max/min value on the graph
 
-    if self._bounds == Bounds.GLOBAL_MAX:
-      primary_max_bound = param.primary.max_value[self._update_interval]
-      secondary_max_bound = param.secondary.max_value[self._update_interval]
+    if self.bounds_type == Bounds.GLOBAL_MAX:
+      primary_max_bound = param.primary.max_value[self.update_interval]
+      secondary_max_bound = param.secondary.max_value[self.update_interval]
     else:
       # both Bounds.LOCAL_MAX and Bounds.TIGHT use local maxima
       if graph_column < 2:
         # nothing being displayed
         primary_max_bound, secondary_max_bound = 0, 0
       else:
-        primary_max_bound = max(param.primary.values[self._update_interval][:graph_column])
-        secondary_max_bound = max(param.secondary.values[self._update_interval][:graph_column])
+        primary_max_bound = max(param.primary.values[self.update_interval][:graph_column])
+        secondary_max_bound = max(param.secondary.values[self.update_interval][:graph_column])
 
     primary_min_bound = secondary_min_bound = 0
 
-    if self._bounds == Bounds.TIGHT:
-      primary_min_bound = min(param.primary.values[self._update_interval][:graph_column])
-      secondary_min_bound = min(param.secondary.values[self._update_interval][:graph_column])
+    if self.bounds_type == Bounds.TIGHT:
+      primary_min_bound = min(param.primary.values[self.update_interval][:graph_column])
+      secondary_min_bound = min(param.secondary.values[self.update_interval][:graph_column])
 
       # if the max = min (ie, all values are the same) then use zero lower
       # bound so a graph is still displayed
@@ -657,13 +658,13 @@ class GraphPanel(panel.Panel):
     # creates bar graph (both primary and secondary)
 
     for col in range(graph_column):
-      column_count = int(param.primary.values[self._update_interval][col]) - primary_min_bound
+      column_count = int(param.primary.values[self.update_interval][col]) - primary_min_bound
       column_height = int(min(self._graph_height, self._graph_height * column_count / (max(1, primary_max_bound) - primary_min_bound)))
 
       for row in range(column_height):
         self.addstr(self._graph_height + 1 - row, col + 5, ' ', curses.A_STANDOUT, PRIMARY_COLOR)
 
-      column_count = int(param.secondary.values[self._update_interval][col]) - secondary_min_bound
+      column_count = int(param.secondary.values[self.update_interval][col]) - secondary_min_bound
       column_height = int(min(self._graph_height, self._graph_height * column_count / (max(1, secondary_max_bound) - secondary_min_bound)))
 
       for row in range(column_height):
@@ -671,7 +672,7 @@ class GraphPanel(panel.Panel):
 
     # bottom labeling of x-axis
 
-    interval_sec = INTERVAL_SECONDS[self._update_interval]
+    interval_sec = INTERVAL_SECONDS[self.update_interval]
 
     interval_spacing = 10 if graph_column >= WIDE_LABELING_GRAPH_COL else 5
     units_label, decimal_precision = None, 0
@@ -697,7 +698,7 @@ class GraphPanel(panel.Panel):
 
     labeling_line = DEFAULT_CONTENT_HEIGHT + self._graph_height - 2
 
-    if self._current_display == GraphStat.BANDWIDTH and width <= COLLAPSE_WIDTH:
+    if self.displayed_stat == GraphStat.BANDWIDTH and width <= COLLAPSE_WIDTH:
       # clears line
 
       self.addstr(labeling_line, 0, ' ' * width)
@@ -714,7 +715,7 @@ class GraphPanel(panel.Panel):
 
     accounting_stats = self.get_attr('_accounting_stats')
 
-    if self._current_display == GraphStat.BANDWIDTH and accounting_stats:
+    if self.displayed_stat == GraphStat.BANDWIDTH and accounting_stats:
       if tor_controller().is_alive():
         hibernate_color = CONFIG['attr.hibernate_color'].get(accounting_stats.status, 'red')
 
@@ -731,29 +732,6 @@ class GraphPanel(panel.Panel):
         self.addstr(labeling_line + 2, 0, 'Accounting:', curses.A_BOLD)
         self.addstr(labeling_line + 2, 12, 'Connection Closed...')
 
-  def get_stats(self):
-    """
-    Provides the currently selected stats label.
-    """
-
-    return self._current_display
-
-  def set_stats(self, label):
-    """
-    Sets the currently displayed stats instance, hiding panel if None.
-    """
-
-    if label != self._current_display:
-      if not label:
-        self._current_display = None
-      elif label in self._stats.keys():
-        self._current_display = label
-      else:
-        raise ValueError('Unrecognized stats label: %s' % label)
-
-  def get_all_stats(self):
-    return self._stats
-
   def copy_attr(self, attr):
     if attr == '_stats':
       return dict([(key, type(self._stats[key])(self._stats[key])) for key in self._stats])
diff --git a/arm/menu/actions.py b/arm/menu/actions.py
index 5608d6b..8b1e4f2 100644
--- a/arm/menu/actions.py
+++ b/arm/menu/actions.py
@@ -149,8 +149,8 @@ def make_graph_menu(graph_panel):
 
   # stats options
 
-  stat_group = arm.menu.item.SelectionGroup(graph_panel.set_stats, graph_panel.get_stats())
-  available_stats = graph_panel.get_all_stats().keys()
+  stat_group = arm.menu.item.SelectionGroup(functools.partial(setattr, graph_panel, 'displayed_stat'), graph_panel.displayed_stat)
+  available_stats = graph_panel.stat_options()
   available_stats.sort()
 
   for stat_key in ["None"] + available_stats:
@@ -165,7 +165,7 @@ def make_graph_menu(graph_panel):
   # interval submenu
 
   interval_menu = arm.menu.item.Submenu("Interval")
-  interval_group = arm.menu.item.SelectionGroup(graph_panel.set_update_interval, graph_panel.get_update_interval())
+  interval_group = arm.menu.item.SelectionGroup(functools.partial(setattr, graph_panel, 'update_interval'), graph_panel.update_interval)
 
   for interval in arm.graph_panel.Interval:
     interval_menu.add(arm.menu.item.SelectionMenuItem(interval, interval_group, interval))
@@ -175,7 +175,7 @@ def make_graph_menu(graph_panel):
   # bounds submenu
 
   bounds_menu = arm.menu.item.Submenu("Bounds")
-  bounds_group = arm.menu.item.SelectionGroup(graph_panel.set_bounds_type, graph_panel.get_bounds_type())
+  bounds_group = arm.menu.item.SelectionGroup(functools.partial(setattr, graph_panel, 'bounds_type'), graph_panel.bounds_type)
 
   for bounds_type in arm.graph_panel.Bounds:
     bounds_menu.add(arm.menu.item.SelectionMenuItem(bounds_type, bounds_group, bounds_type))
diff --git a/arm/util/panel.py b/arm/util/panel.py
index fb6ae0e..9320270 100644
--- a/arm/util/panel.py
+++ b/arm/util/panel.py
@@ -53,7 +53,7 @@ for color_label in ui_tools.COLOR_LIST:
 HALT_ACTIVITY = False
 
 
-class Panel():
+class Panel(object):
   """
   Wrapper for curses subwindows. This hides most of the ugliness in common
   curses operations including:





More information about the tor-commits mailing list