[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