commit ec41f9b795f03efbd29fec3cb6ea831faa40532b Author: Damian Johnson atagar@torproject.org Date: Wed Dec 19 08:23:03 2012 -0800
Using stem's enum util
Replacing our Enum class with stem's. This is the start of a general migration to stem's utility classes, which unlike ours actually have tests (yay!). --- src/cli/configPanel.py | 10 ++- src/cli/connections/connEntry.py | 6 +- src/cli/connections/connPanel.py | 18 +++--- src/cli/connections/countPopup.py | 4 +- src/cli/connections/entries.py | 2 +- src/cli/controller.py | 4 +- src/cli/graphing/graphPanel.py | 6 +- src/cli/logPanel.py | 22 ++++---- src/cli/menu/actions.py | 6 +- src/cli/torrcPanel.py | 4 +- src/test.py | 4 +- src/util/__init__.py | 2 +- src/util/conf.py | 2 +- src/util/connections.py | 4 +- src/util/enum.py | 116 ------------------------------------- src/util/log.py | 11 ++-- src/util/procTools.py | 4 +- src/util/torConfig.py | 6 +- src/util/torTools.py | 4 +- src/util/uiTools.py | 4 +- 20 files changed, 73 insertions(+), 166 deletions(-)
diff --git a/src/cli/configPanel.py b/src/cli/configPanel.py index a73f2a8..50b66b3 100644 --- a/src/cli/configPanel.py +++ b/src/cli/configPanel.py @@ -9,7 +9,9 @@ import threading import cli.controller import popups
-from util import conf, enum, panel, sysTools, torConfig, torTools, uiTools +from util import conf, panel, sysTools, torConfig, torTools, uiTools + +from stem.util import enum
DEFAULT_CONFIG = {"features.config.selectionDetails.height": 6, "features.config.prepopulateEditValues": True, @@ -182,7 +184,7 @@ class ConfigPanel(panel.Panel): "features.config.state.colWidth.option": 5, "features.config.state.colWidth.value": 5})
- sortFields = Field.values() + sortFields = list(Field) customOrdering = config.getIntCSV("features.config.order", None, 3, 0, len(sortFields))
if customOrdering: @@ -300,9 +302,9 @@ class ConfigPanel(panel.Panel):
# set ordering for config options titleLabel = "Config Option Ordering:" - options = [FIELD_ATTR[field][0] for field in Field.values()] + options = [FIELD_ATTR[field][0] for field in Field] oldSelection = [FIELD_ATTR[field][0] for field in self.sortOrdering] - optionColors = dict([FIELD_ATTR[field] for field in Field.values()]) + optionColors = dict([FIELD_ATTR[field] for field in Field]) results = popups.showSortDialog(titleLabel, options, oldSelection, optionColors)
if results: diff --git a/src/cli/connections/connEntry.py b/src/cli/connections/connEntry.py index 7650149..2f57b51 100644 --- a/src/cli/connections/connEntry.py +++ b/src/cli/connections/connEntry.py @@ -6,9 +6,11 @@ Connection panel entries related to actual connections to or from the system import time import curses
-from util import connections, enum, torTools, uiTools +from util import connections, torTools, uiTools from cli.connections import entries
+from stem.util import enum + # Connection Categories: # Inbound Relay connection, coming to us. # Outbound Relay connection, leaving us. @@ -178,7 +180,7 @@ class ConnectionEntry(entries.ConnectionPanelEntry): if myNickname == "UNKNOWN": return "z" * 20 # orders at the end else: return myNickname.lower() elif attr == entries.SortAttr.CATEGORY: - return Category.indexOf(connLine.getType()) + return Category.index_of(connLine.getType()) elif attr == entries.SortAttr.UPTIME: return connLine.startTime elif attr == entries.SortAttr.COUNTRY: diff --git a/src/cli/connections/connPanel.py b/src/cli/connections/connPanel.py index 632669c..50ba2e8 100644 --- a/src/cli/connections/connPanel.py +++ b/src/cli/connections/connPanel.py @@ -10,7 +10,9 @@ import threading import cli.popups
from cli.connections import countPopup, descriptorPopup, entries, connEntry, circEntry -from util import connections, enum, panel, torTools, uiTools +from util import connections, panel, torTools, uiTools + +from stem.util import enum
DEFAULT_CONFIG = {"features.connection.resolveApps": True, "features.connection.listingType": 0, @@ -41,7 +43,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
if config: config.update(self._config, { - "features.connection.listingType": (0, len(Listing.values()) - 1), + "features.connection.listingType": (0, len(list(Listing)) - 1), "features.connection.refreshRate": 1})
# defaults our listing selection to fingerprints if ip address @@ -49,13 +51,13 @@ class ConnectionPanel(panel.Panel, threading.Thread): if not self._config["features.connection.showIps"] and self._config["features.connection.listingType"] == 0: self._config["features.connection.listingType"] = 2
- sortFields = entries.SortAttr.values() + sortFields = list(entries.SortAttr) customOrdering = config.getIntCSV("features.connection.order", None, 3, 0, len(sortFields))
if customOrdering: self._sortOrdering = [sortFields[i] for i in customOrdering]
- self._listingType = Listing.values()[self._config["features.connection.listingType"]] + self._listingType = list(Listing)[self._config["features.connection.listingType"]] self._scroller = uiTools.Scroller(True) self._title = "Connections:" # title line of the panel self._entries = [] # last fetched display entries @@ -205,7 +207,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
# set ordering for connection options titleLabel = "Connection Ordering:" - options = entries.SortAttr.values() + options = list(entries.SortAttr) oldSelection = self._sortOrdering optionColors = dict([(attr, entries.SORT_COLORS[attr]) for attr in options]) results = cli.popups.showSortDialog(titleLabel, options, oldSelection, optionColors) @@ -228,7 +230,7 @@ class ConnectionPanel(panel.Panel, threading.Thread): elif key == ord('u') or key == ord('U'): # provides a menu to pick the connection resolver title = "Resolver Util:" - options = ["auto"] + connections.Resolver.values() + options = ["auto"] + list(connections.Resolver) connResolver = connections.getResolver("tor")
currentOverwrite = connResolver.overwriteResolver @@ -244,7 +246,7 @@ class ConnectionPanel(panel.Panel, threading.Thread): elif key == ord('l') or key == ord('L'): # provides a menu to pick the primary information we list connections by title = "List By:" - options = entries.ListingType.values() + options = list(entries.ListingType)
# dropping the HOSTNAME listing type until we support displaying that content options.remove(cli.connections.entries.ListingType.HOSTNAME) @@ -489,7 +491,7 @@ class ConnectionPanel(panel.Panel, threading.Thread): # type cache for all of the connections (in case its changed since last # fetched).
- categoryTypes = connEntry.Category.values() + categoryTypes = list(connEntry.Category) typeCounts = dict((type, 0) for type in categoryTypes) for entry in newEntries: if isinstance(entry, connEntry.ConnectionEntry): diff --git a/src/cli/connections/countPopup.py b/src/cli/connections/countPopup.py index 7904519..7ec6e60 100644 --- a/src/cli/connections/countPopup.py +++ b/src/cli/connections/countPopup.py @@ -8,7 +8,9 @@ import operator import cli.controller import cli.popups
-from util import connections, enum, log, uiTools +from util import connections, log, uiTools + +from stem.util import enum
CountType = enum.Enum("CLIENT_LOCALE", "EXIT_PORT") EXIT_USAGE_WIDTH = 15 diff --git a/src/cli/connections/entries.py b/src/cli/connections/entries.py index f832b6a..d5085aa 100644 --- a/src/cli/connections/entries.py +++ b/src/cli/connections/entries.py @@ -4,7 +4,7 @@ entry itself (ie, Tor connection, client circuit, etc) and the lines it consists of in the listing. """
-from util import enum +from stem.util import enum
# attributes we can list entries by ListingType = enum.Enum(("IP_ADDRESS", "IP Address"), "HOSTNAME", "FINGERPRINT", "NICKNAME") diff --git a/src/cli/controller.py b/src/cli/controller.py index 478bc02..af3fdac 100644 --- a/src/cli/controller.py +++ b/src/cli/controller.py @@ -22,7 +22,9 @@ import cli.connections.connPanel
from stem.control import Controller
-from util import connections, conf, enum, hostnames, log, panel, sysTools, torConfig, torTools +from util import connections, conf, hostnames, log, panel, sysTools, torConfig, torTools + +from stem.util import enum
ARM_CONTROLLER = None
diff --git a/src/cli/graphing/graphPanel.py b/src/cli/graphing/graphPanel.py index d03d1bd..16efe8f 100644 --- a/src/cli/graphing/graphPanel.py +++ b/src/cli/graphing/graphPanel.py @@ -24,7 +24,9 @@ import cli.controller
import stem.control
-from util import enum, panel, torTools, uiTools +from util import panel, torTools, uiTools + +from stem.util import enum
# time intervals at which graphs can be updated UPDATE_INTERVALS = [("each second", 1), ("5 seconds", 5), ("30 seconds", 30), @@ -232,7 +234,7 @@ class GraphPanel(panel.Panel): def __init__(self, stdscr): panel.Panel.__init__(self, stdscr, "graph", 0) self.updateInterval = CONFIG["features.graph.interval"] - self.bounds = Bounds.values()[CONFIG["features.graph.bound"]] + self.bounds = list(Bounds)[CONFIG["features.graph.bound"]] self.graphHeight = CONFIG["features.graph.height"] self.currentDisplay = None # label of the stats currently being displayed self.stats = {} # available stats (mappings of label -> instance) diff --git a/src/cli/logPanel.py b/src/cli/logPanel.py index b866c62..d03973d 100644 --- a/src/cli/logPanel.py +++ b/src/cli/logPanel.py @@ -120,9 +120,9 @@ def expandEvents(eventAbbr):
for flag in eventAbbr: if flag == "A": - armRunlevels = ["ARM_" + runlevel for runlevel in log.Runlevel.values()] - stemRunlevels = ["STEM_" + runlevel for runlevel in log.Runlevel.values()] - expandedEvents = set(TOR_EVENT_TYPES.values() + armRunlevels + stemRunlevels + ["UNKNOWN"]) + armRunlevels = ["ARM_" + runlevel for runlevel in log.Runlevel] + stemRunlevels = ["STEM_" + runlevel for runlevel in log.Runlevel] + expandedEvents = set(list(TOR_EVENT_TYPES) + armRunlevels + stemRunlevels + ["UNKNOWN"]) break elif flag == "X": expandedEvents = set() @@ -136,11 +136,11 @@ def expandEvents(eventAbbr): elif flag in "E5": runlevelIndex = 4
if flag in "DINWE": - runlevelSet = [runlevel for runlevel in log.Runlevel.values()[runlevelIndex:]] + runlevelSet = [runlevel for runlevel in list(log.Runlevel)[runlevelIndex:]] expandedEvents = expandedEvents.union(set(runlevelSet)) elif flag in "12345": for prefix in ("ARM_", "STEM_"): - runlevelSet = [prefix + runlevel for runlevel in log.Runlevel.values()[runlevelIndex:]] + runlevelSet = [prefix + runlevel for runlevel in list(log.Runlevel)[runlevelIndex:]] expandedEvents = expandedEvents.union(set(runlevelSet)) elif flag == "U": expandedEvents.add("UNKNOWN") @@ -219,7 +219,7 @@ def getLogFileEntries(runlevels, readLimit = None, addLimit = None, config = Non
# if the runlevels argument is a superset of the log file then we can # limit the read contents to the addLimit - runlevels = log.Runlevel.values() + runlevels = list(log.Runlevel) loggingTypes = loggingTypes.upper() if addLimit and (not readLimit or readLimit > addLimit): if "-" in loggingTypes: @@ -550,7 +550,7 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler): # adds arm listener and prepopulates log with past tor/arm events log.LOG_LOCK.acquire() try: - log.addListeners(log.Runlevel.values(), self._registerArmEvent) + log.addListeners(list(log.Runlevel), self._registerArmEvent) self.reprepopulateEvents() finally: log.LOG_LOCK.release() @@ -597,16 +597,16 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler): # fetches past tor events from log file, if available torEventBacklog = [] if self._config["features.log.prepopulate"]: - setRunlevels = list(set.intersection(set(self.loggedEvents), set(log.Runlevel.values()))) + setRunlevels = list(set.intersection(set(self.loggedEvents), set(list(log.Runlevel)))) readLimit = self._config["features.log.prepopulateReadLimit"] addLimit = self._config["cache.logPanel.size"] torEventBacklog = getLogFileEntries(setRunlevels, readLimit, addLimit, self._config)
# gets the set of arm events we're logging setRunlevels = [] - armRunlevels = log.Runlevel.values() + armRunlevels = list(log.Runlevel) for i in range(len(armRunlevels)): - if "ARM_" + log.Runlevel.values()[i] in self.loggedEvents: + if "ARM_" + list(log.Runlevel)[i] in self.loggedEvents: setRunlevels.append(armRunlevels[i])
armEventBacklog = [] @@ -1213,7 +1213,7 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler): runlevelRanges = [] # tuple of type, startLevel, endLevel for ranges to be consensed
# reverses runlevels and types so they're appended in the right order - reversedRunlevels = log.Runlevel.values() + reversedRunlevels = list(log.Runlevel) reversedRunlevels.reverse() for prefix in ("STEM_", "ARM_", ""): # blank ending runlevel forces the break condition to be reached at the end diff --git a/src/cli/menu/actions.py b/src/cli/menu/actions.py index 30dff69..b1371c4 100644 --- a/src/cli/menu/actions.py +++ b/src/cli/menu/actions.py @@ -157,7 +157,7 @@ def makeGraphMenu(graphPanel): boundsMenu = cli.menu.item.Submenu("Bounds") boundsGroup = cli.menu.item.SelectionGroup(graphPanel.setBoundsType, graphPanel.getBoundsType())
- for boundsType in cli.graphing.graphPanel.Bounds.values(): + for boundsType in cli.graphing.graphPanel.Bounds: boundsMenu.add(cli.menu.item.SelectionMenuItem(boundsType, boundsGroup, boundsType))
graphMenu.add(boundsMenu) @@ -219,7 +219,7 @@ def makeConnectionsMenu(connPanel): # listing options listingGroup = cli.menu.item.SelectionGroup(connPanel.setListingType, connPanel.getListingType())
- listingOptions = cli.connections.entries.ListingType.values() + listingOptions = list(cli.connections.entries.ListingType) listingOptions.remove(cli.connections.entries.ListingType.HOSTNAME)
for option in listingOptions: @@ -235,7 +235,7 @@ def makeConnectionsMenu(connPanel):
resolverMenu.add(cli.menu.item.SelectionMenuItem("auto", resolverGroup, None))
- for option in connections.Resolver.values(): + for option in connections.Resolver: resolverMenu.add(cli.menu.item.SelectionMenuItem(option, resolverGroup, option))
connectionsMenu.add(resolverMenu) diff --git a/src/cli/torrcPanel.py b/src/cli/torrcPanel.py index c1bb3f9..983768f 100644 --- a/src/cli/torrcPanel.py +++ b/src/cli/torrcPanel.py @@ -8,7 +8,9 @@ import threading
import popups
-from util import conf, enum, panel, torConfig, torTools, uiTools +from util import conf, panel, torConfig, torTools, uiTools + +from stem.util import enum
DEFAULT_CONFIG = {"features.config.file.showScrollbars": True, "features.config.file.maxLinesPerEntry": 8} diff --git a/src/test.py b/src/test.py index 7129120..10eddb0 100644 --- a/src/test.py +++ b/src/test.py @@ -68,7 +68,7 @@ while True: # provide the selection options printDivider() print("Select a resolver:") - availableResolvers = connections.Resolver.values() + availableResolvers = list(connections.Resolver) for i in range(len(availableResolvers)): print(" %i. %s" % (i, availableResolvers[i])) print(" q. Go back to the main menu") @@ -80,7 +80,7 @@ while True:
if userSelection.isdigit() and int(userSelection) in range(0, 7): try: - resolver = connections.Resolver.values()[int(userSelection)] + resolver = list(connections.Resolver)[int(userSelection)] startTime = time.time()
print(connections.getResolverCommand(resolver, "tor", conn.getMyPid())) diff --git a/src/util/__init__.py b/src/util/__init__.py index 5afde12..e4e22c1 100644 --- a/src/util/__init__.py +++ b/src/util/__init__.py @@ -4,5 +4,5 @@ application's status, making cross platform system calls, parsing tor data, and safely working with curses (hiding some of the gory details). """
-__all__ = ["conf", "connections", "enum", "hostnames", "log", "panel", "procTools", "procName", "sysTools", "textInput", "torConfig", "torTools", "uiTools"] +__all__ = ["conf", "connections", "hostnames", "log", "panel", "procTools", "procName", "sysTools", "textInput", "torConfig", "torTools", "uiTools"]
diff --git a/src/util/conf.py b/src/util/conf.py index bfbf468..a8ca6de 100644 --- a/src/util/conf.py +++ b/src/util/conf.py @@ -111,7 +111,7 @@ class Config():
if key.startswith("log."): if val.upper() == "NONE": val = None - elif val.upper() in log.Runlevel.values(): val = val.upper() + elif val.upper() in list(log.Runlevel): val = val.upper() else: msg = "Config entry '%s' is expected to be a runlevel" % key if default != None: msg += ", defaulting to '%s'" % default diff --git a/src/util/connections.py b/src/util/connections.py index 250b113..de128c2 100644 --- a/src/util/connections.py +++ b/src/util/connections.py @@ -21,7 +21,9 @@ import os import time import threading
-from util import enum, log, procTools, sysTools +from util import log, procTools, sysTools + +from stem.util import enum
# enums for connection resolution utilities Resolver = enum.Enum(("PROC", "proc"), diff --git a/src/util/enum.py b/src/util/enum.py deleted file mode 100644 index bdba6b4..0000000 --- a/src/util/enum.py +++ /dev/null @@ -1,116 +0,0 @@ -""" -Basic enumeration, providing ordered types for collections. These can be -constructed as simple type listings, ie: ->>> insects = Enum("ANT", "WASP", "LADYBUG", "FIREFLY") ->>> insects.ANT -'Ant' ->>> insects.values() -['Ant', 'Wasp', 'Ladybug', 'Firefly'] - -with overwritten string counterparts: ->>> pets = Enum(("DOG", "Skippy"), "CAT", ("FISH", "Nemo")) ->>> pets.DOG -'Skippy' ->>> pets.CAT -'Cat' - -or with entirely custom string components as an unordered enum with: ->>> pets = LEnum(DOG="Skippy", CAT="Kitty", FISH="Nemo") ->>> pets.CAT -'Kitty' -""" - -def toCamelCase(label): - """ - Converts the given string to camel case, ie: - >>> toCamelCase("I_LIKE_PEPPERJACK!") - 'I Like Pepperjack!' - - Arguments: - label - input string to be converted - """ - - words = [] - for entry in label.split("_"): - if len(entry) == 0: words.append("") - elif len(entry) == 1: words.append(entry.upper()) - else: words.append(entry[0].upper() + entry[1:].lower()) - - return " ".join(words) - -class Enum: - """ - Basic enumeration. - """ - - def __init__(self, *args): - self.orderedValues = [] - - for entry in args: - if isinstance(entry, str): - key, val = entry, toCamelCase(entry) - elif isinstance(entry, tuple) and len(entry) == 2: - key, val = entry - else: raise ValueError("Unrecognized input: %s" % args) - - self.__dict__[key] = val - self.orderedValues.append(val) - - def values(self): - """ - Provides an ordered listing of the enumerations in this set. - """ - - return list(self.orderedValues) - - def indexOf(self, value): - """ - Provides the index of the given value in the collection. This raises a - ValueError if no such element exists. - - Arguments: - value - entry to be looked up - """ - - return self.orderedValues.index(value) - - def next(self, value): - """ - Provides the next enumeration after the given value, raising a ValueError - if no such enum exists. - - Arguments: - value - enumeration for which to get the next entry - """ - - if not value in self.orderedValues: - raise ValueError("No such enumeration exists: %s (options: %s)" % (value, ", ".join(self.orderedValues))) - - nextIndex = (self.orderedValues.index(value) + 1) % len(self.orderedValues) - return self.orderedValues[nextIndex] - - def previous(self, value): - """ - Provides the previous enumeration before the given value, raising a - ValueError if no such enum exists. - - Arguments: - value - enumeration for which to get the previous entry - """ - - if not value in self.orderedValues: - raise ValueError("No such enumeration exists: %s (options: %s)" % (value, ", ".join(self.orderedValues))) - - prevIndex = (self.orderedValues.index(value) - 1) % len(self.orderedValues) - return self.orderedValues[prevIndex] - -class LEnum(Enum): - """ - Enumeration that accepts custom string mappings. - """ - - def __init__(self, **args): - Enum.__init__(self) - self.__dict__.update(args) - self.orderedValues = sorted(args.values()) - diff --git a/src/util/log.py b/src/util/log.py index e4bd231..56a6636 100644 --- a/src/util/log.py +++ b/src/util/log.py @@ -11,23 +11,22 @@ import time from sys import maxint from threading import RLock
-from util import enum +from stem.util import enum
# Logging runlevels. These are *very* commonly used so including shorter # aliases (so they can be referenced as log.DEBUG, log.WARN, etc). -Runlevel = enum.Enum(("DEBUG", "DEBUG"), ("INFO", "INFO"), ("NOTICE", "NOTICE"), - ("WARN", "WARN"), ("ERR", "ERR")) -DEBUG, INFO, NOTICE, WARN, ERR = Runlevel.values() +Runlevel = enum.UppercaseEnum("DEBUG", "INFO", "NOTICE", "WARN", "ERR") +DEBUG, INFO, NOTICE, WARN, ERR = list(Runlevel)
# provides thread safety for logging operations LOG_LOCK = RLock()
# chronologically ordered records of events for each runlevel, stored as tuples # consisting of: (time, message) -_backlog = dict([(level, []) for level in Runlevel.values()]) +_backlog = dict([(level, []) for level in Runlevel])
# mapping of runlevels to the listeners interested in receiving events from it -_listeners = dict([(level, []) for level in Runlevel.values()]) +_listeners = dict([(level, []) for level in Runlevel])
CONFIG = {"cache.armLog.size": 1000, "cache.armLog.trimSize": 200} diff --git a/src/util/procTools.py b/src/util/procTools.py index 39b5407..835814e 100644 --- a/src/util/procTools.py +++ b/src/util/procTools.py @@ -20,7 +20,9 @@ import time import socket import base64
-from util import enum, log +from util import log + +from stem.util import enum
# cached system values SYS_START_TIME, SYS_PHYSICAL_MEMORY = None, None diff --git a/src/util/torConfig.py b/src/util/torConfig.py index 0f6452d..5566e9d 100644 --- a/src/util/torConfig.py +++ b/src/util/torConfig.py @@ -9,7 +9,9 @@ import threading
import stem.version
-from util import enum, log, sysTools, torTools, uiTools +from util import log, sysTools, torTools, uiTools + +from stem.util import enum
CONFIG = {"features.torrc.validate": True, "config.important": [], @@ -147,7 +149,7 @@ def loadOptionDescriptions(loadPath = None, checkVersion = True): while inputFileContents: # gets category enum, failing if it doesn't exist category = inputFileContents.pop(0).rstrip() - if not category in Category.values(): + if not category in Category: baseMsg = "invalid category in input file: '%s'" raise IOError(baseMsg % category)
diff --git a/src/util/torTools.py b/src/util/torTools.py index a5add1a..7aea8fa 100644 --- a/src/util/torTools.py +++ b/src/util/torTools.py @@ -16,7 +16,9 @@ import stem import stem.control import stem.descriptor
-from util import connections, enum, log, procTools, sysTools, uiTools +from util import connections, log, procTools, sysTools, uiTools + +from stem.util import enum
# enums for tor's controller state: # INIT - attached to a new controller diff --git a/src/util/uiTools.py b/src/util/uiTools.py index bc1fefe..c1f1a86 100644 --- a/src/util/uiTools.py +++ b/src/util/uiTools.py @@ -10,7 +10,9 @@ import sys import curses
from curses.ascii import isprint -from util import enum, log +from util import log + +from stem.util import enum
# colors curses can handle COLOR_LIST = {"red": curses.COLOR_RED, "green": curses.COLOR_GREEN,
tor-commits@lists.torproject.org