[tor-commits] [stem/master] Dropping Config.sync() in favor of config_dict()

atagar at torproject.org atagar at torproject.org
Wed Jan 25 16:51:01 UTC 2012


commit 030579292593a9e8262edfc713e1d86b379dabf5
Author: Damian Johnson <atagar at torproject.org>
Date:   Wed Jan 25 08:48:48 2012 -0800

    Dropping Config.sync() in favor of config_dict()
    
    The Config class' sync method was a step in the right direction, but the name
    was confusing and the usage was suboptimal. In the vast majority of cases the
    caller simply wants a dictionary that stays in sync with the configuration. The
    config_dict() function is essentially the same as sync but with more succinct
    calls.
---
 run_tests.py           |    6 ++--
 stem/util/conf.py      |   70 ++++++++++++++++++++++++++-------------------
 test/output.py         |    6 +--
 test/runner.py         |    6 +--
 test/unit/util/conf.py |   74 ++++++++++++++++++++++++------------------------
 5 files changed, 85 insertions(+), 77 deletions(-)

diff --git a/run_tests.py b/run_tests.py
index 6972e16..d4d2fd6 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -29,6 +29,7 @@ import test.integ.util.conf
 import test.integ.util.system
 import test.integ.version
 
+import stem.util.conf
 import stem.util.enum
 import stem.util.log as log
 import stem.util.term as term
@@ -37,7 +38,7 @@ OPT = "uic:l:t:h"
 OPT_EXPANDED = ["unit", "integ", "config=", "targets=", "log=", "tor=", "no-color", "help"]
 DIVIDER = "=" * 70
 
-CONFIG = {
+CONFIG = stem.util.conf.config_dict("test", {
   "argument.unit": False,
   "argument.integ": False,
   "argument.log": None,
@@ -48,7 +49,7 @@ CONFIG = {
   "target.description": {},
   "target.prereq": {},
   "target.torrc": {},
-}
+})
 
 Target = stem.util.enum.Enum(*[(v, v) for v in (
   "ONLINE",
@@ -183,7 +184,6 @@ if __name__ == '__main__':
   
   # loads and validates our various configurations
   test_config = stem.util.conf.get_config("test")
-  test_config.sync(CONFIG)
   
   settings_path = os.path.join(test.runner.STEM_BASE, "test", "settings.cfg")
   test_config.load(settings_path)
diff --git a/stem/util/conf.py b/stem/util/conf.py
index 9250053..fe8ab68 100644
--- a/stem/util/conf.py
+++ b/stem/util/conf.py
@@ -19,6 +19,26 @@ a '|' prefix. For instance...
   |exclaiming about the wonders
   |and awe that is pepperjack!
 
+The Config class acts as a central store for configuration values. Users of
+this store have their own dictionaries of config key/value pairs that provide
+three things...
+
+  1. Default values for the configuration keys in case they're either undefined
+     or of the wrong type.
+  2. Types that we should attempt to cast the configuration values to.
+  3. An easily accessable container for getting the config values.
+
+There are many ways of using the Config class but the most common ones are...
+
+- Call config_dict to get a dictionary that's always synced with with a Config.
+
+- Make a dictionary and call synchronize() to bring it into sync with the
+  Config. This does not keep it in sync as the Config changes. See the Config
+  class' pydocs for an example.
+
+- Just call the Config's get() or get_value() methods directly.
+
+config_dict - provides a dictionary that's kept synchronized with a config
 get_config - Singleton for getting configurations
 Config - Custom configuration.
   |- load - reads a configuration file
@@ -27,7 +47,6 @@ Config - Custom configuration.
   |- synchronize - replaces mappings in a dictionary with the config's values
   |- add_listener - notifies the given listener when an update occures
   |- clear_listeners - removes any attached listeners
-  |- sync - keeps a dictionary synchronized with our config
   |- keys - provides keys in the loaded configuration
   |- set - sets the given key/value pair
   |- unused_keys - provides keys that have never been requested
@@ -59,14 +78,27 @@ class SyncListener:
       
       self.config_dict[key] = new_value
 
-# TODO: methods that will be needed if we want to allow for runtime
-# customization...
-#
-# Config.set(key, value) - accepts any type that the get() method does,
-#   updating our contents with the string conversion
-#
-# Config.save(path) - writes our current configurations, ideally merging them
-#   with the file that exists there so commenting and such are preserved
+def config_dict(handle, conf_mappings, handler = None):
+  """
+  Makes a dictionary that stays synchronized with a configuration. The process
+  for staying in sync is similar to the Config class' synchronize() method,
+  only changing the dictionary's values if we're able to cast to the same type.
+  
+  If an handler is provided then this is called just prior to assigning new
+  values to the config_dict. The handler function is expected to accept the
+  (key, value) for the new values and return what we should actually insert
+  into the dictionary. If this returns None then the value is updated as
+  normal.
+  
+  Arguments:
+    handle (str)         - unique identifier for a config instance
+    conf_mappings (dict) - config key/value mappings used as our defaults
+    handler (functor)    - function referred to prior to assigning values
+  """
+  
+  selected_config = get_config(handle)
+  selected_config.add_listener(SyncListener(conf_mappings, handler).update)
+  return conf_mappings
 
 def get_config(handle):
   """
@@ -312,26 +344,6 @@ class Config():
     
     self._listeners = []
   
-  def sync(self, config_dict, interceptor = None):
-    """
-    Synchronizes a dictionary with our current configuration (like the
-    'synchronize' method), and registers it to be updated whenever our
-    configuration changes.
-    
-    If an interceptor is provided then this is called just prior to assigning
-    new values to the config_dict. The interceptor function is expected to
-    accept the (key, value) for the new values and return what we should
-    actually insert into the dictionary. If this returns None then the value is
-    updated as normal.
-    
-    Arguments:
-      config_dict (dict)    - dictionary to keep synchronized with our
-                              configuration
-      interceptor (functor) - function referred to prior to assigning values
-    """
-    
-    self.add_listener(SyncListener(config_dict, interceptor).update)
-  
   def keys(self):
     """
     Provides all keys in the currently loaded configuration.
diff --git a/test/output.py b/test/output.py
index 76156b9..89a6cc0 100644
--- a/test/output.py
+++ b/test/output.py
@@ -11,11 +11,9 @@ import stem.util.conf
 import stem.util.enum
 import stem.util.term as term
 
-CONFIG = {
+CONFIG = stem.util.conf.config_dict("test", {
   "argument.no_color": False,
-}
-
-stem.util.conf.get_config("test").sync(CONFIG)
+})
 
 DIVIDER = "=" * 70
 HEADER_ATTR = (term.Color.CYAN, term.Attr.BOLD)
diff --git a/test/runner.py b/test/runner.py
index 405f96c..d3c6143 100644
--- a/test/runner.py
+++ b/test/runner.py
@@ -41,14 +41,12 @@ import stem.util.enum
 import stem.util.term as term
 import test.output
 
-CONFIG = {
+CONFIG = stem.util.conf.config_dict("test", {
   "integ.test_directory": "./test/data",
   "integ.log": "./test/data/log",
   "test.target.online": False,
   "test.target.relative_data_dir": False,
-}
-
-stem.util.conf.get_config("test").sync(CONFIG)
+})
 
 STATUS_ATTR = (term.Color.BLUE, term.Attr.BOLD)
 SUBSTATUS_ATTR = (term.Color.BLUE, )
diff --git a/test/unit/util/conf.py b/test/unit/util/conf.py
index 7df0402..0a31381 100644
--- a/test/unit/util/conf.py
+++ b/test/unit/util/conf.py
@@ -16,6 +16,43 @@ class TestConf(unittest.TestCase):
     test_config.clear()
     test_config.clear_listeners()
   
+  def test_config_dict(self):
+    """
+    Tests the config_dict function.
+    """
+    
+    my_config = {
+      "bool_value": False,
+      "int_value": 5,
+      "str_value": "hello",
+      "list_value": [],
+    }
+    
+    test_config = stem.util.conf.get_config("unit_testing")
+    
+    # checks that sync causes existing contents to be applied
+    test_config.set("bool_value", "true")
+    my_config = stem.util.conf.config_dict("unit_testing", my_config)
+    self.assertEquals(True, my_config["bool_value"])
+    
+    # check a basic synchronize
+    test_config.set("str_value", "me")
+    self.assertEquals("me", my_config["str_value"])
+    
+    # synchronize with a type mismatch, should keep the old value
+    test_config.set("int_value", "7a")
+    self.assertEquals(5, my_config["int_value"])
+    
+    # changes for a collection
+    test_config.set("list_value", "a", False)
+    self.assertEquals(["a"], my_config["list_value"])
+    
+    test_config.set("list_value", "b", False)
+    self.assertEquals(["a", "b"], my_config["list_value"])
+    
+    test_config.set("list_value", "c", False)
+    self.assertEquals(["a", "b", "c"], my_config["list_value"])
+  
   def test_clear(self):
     """
     Tests the clear method.
@@ -113,43 +150,6 @@ class TestConf(unittest.TestCase):
     test_config.set("foo", "bar")
     self.assertEquals(["hello"], listener_received_keys)
   
-  def test_sync(self):
-    """
-    Tests the sync method.
-    """
-    
-    my_config = {
-      "bool_value": False,
-      "int_value": 5,
-      "str_value": "hello",
-      "list_value": [],
-    }
-    
-    test_config = stem.util.conf.get_config("unit_testing")
-    
-    # checks that sync causes existing contents to be applied
-    test_config.set("bool_value", "true")
-    test_config.sync(my_config)
-    self.assertEquals(True, my_config["bool_value"])
-    
-    # check a basic synchronize
-    test_config.set("str_value", "me")
-    self.assertEquals("me", my_config["str_value"])
-    
-    # synchronize with a type mismatch, should keep the old value
-    test_config.set("int_value", "7a")
-    self.assertEquals(5, my_config["int_value"])
-    
-    # changes for a collection
-    test_config.set("list_value", "a", False)
-    self.assertEquals(["a"], my_config["list_value"])
-    
-    test_config.set("list_value", "b", False)
-    self.assertEquals(["a", "b"], my_config["list_value"])
-    
-    test_config.set("list_value", "c", False)
-    self.assertEquals(["a", "b", "c"], my_config["list_value"])
-  
   def test_unused_keys(self):
     """
     Tests the unused_keys method.



More information about the tor-commits mailing list