summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipalib/__init__.py1
-rw-r--r--ipalib/cli.py7
-rw-r--r--ipalib/config.py40
-rw-r--r--ipalib/plugable.py54
-rw-r--r--ipalib/tests/test_crud.py2
-rw-r--r--ipalib/tests/test_frontend.py10
-rw-r--r--ipalib/tests/test_plugable.py83
-rw-r--r--ipalib/tests/tstutil.py6
8 files changed, 152 insertions, 51 deletions
diff --git a/ipalib/__init__.py b/ipalib/__init__.py
index f0d43aadd..956e46101 100644
--- a/ipalib/__init__.py
+++ b/ipalib/__init__.py
@@ -61,7 +61,6 @@ import backend
import config
api = plugable.API(
- config.default_environment(),
frontend.Command,
frontend.Object,
frontend.Method,
diff --git a/ipalib/cli.py b/ipalib/cli.py
index 1a08cef41..d66e1e2eb 100644
--- a/ipalib/cli.py
+++ b/ipalib/cli.py
@@ -29,8 +29,7 @@ import frontend
import errors
import plugable
import ipa_types
-
-from ipalib import config
+import config
def exit_error(error):
sys.exit('ipa: ERROR: %s' % error)
@@ -257,9 +256,7 @@ class CLI(object):
self.print_commands()
print 'Usage: ipa COMMAND'
sys.exit(2)
- # do parsing here, read the conf
- conf_dict = config.read_config(self.api.env.conf)
- self.api.env.update(conf_dict)
+ self.api.env.update(config.generate_env())
key = sys.argv[1]
if key not in self:
self.print_commands()
diff --git a/ipalib/config.py b/ipalib/config.py
index bb345661c..73d23c8e0 100644
--- a/ipalib/config.py
+++ b/ipalib/config.py
@@ -17,22 +17,31 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+import types
-def default_environment():
+DEFAULT_CONF='/etc/ipa/ipa.conf'
+
+def generate_env(d={}):
default = dict(
- conf = '/etc/ipa/ipa.conf',
server_context = True,
query_dns = True,
verbose = False,
- servers = LazyIter(myservers),
- realm = LazyProp(myrealm),
- domain = LazyProp(mydomain),
+ servers = LazyIter(get_servers),
+ realm = LazyProp(get_realm),
+ domain = LazyProp(get_domain),
)
+ for key, value in d.iteritems():
+ if key in default and type(default[key]) in (LazyIter, LazyProp):
+ default[key].set_value(value)
+ else:
+ default[key] = value
+
return default
class LazyProp(object):
def __init__(self, func, value=None):
+ assert isinstance(func, types.FunctionType)
self._func = func
self._value = value
@@ -40,26 +49,26 @@ class LazyProp(object):
self._value = value
def get_value(self):
- if self._value is None:
+ if self._value == None:
return self._func()
else:
return self._value
-# FIXME: make sure to eliminate duplicates
class LazyIter(LazyProp):
def get_value(self):
- if self._value is not None:
- if type(self._value) is tuple:
+ if self._value != None:
+ if type(self._value) == tuple:
for item in self._value:
yield item
else:
yield self._value
for item in self._func():
- yield item
+ if not self._value or item not in self._value:
+ yield item
-def read_config(file):
+def read_config(file=DEFAULT_CONF):
assert isinstance(file, basestring)
# open the file and read configuration, return a dict
# for now, these are here just for testing purposes
@@ -67,18 +76,15 @@ def read_config(file):
# these functions are here just to "emulate" dns resolving for now
-def mydomain():
+def get_domain():
return "ipatest.com"
-def myrealm():
+def get_realm():
return "IPATEST.COM"
-def myservers():
- # print is here to demonstrate that the querying will occur only when it is
- # really needed
- print "Querying DNS"
+def get_servers():
yield "server.ipatest.com"
yield "backup.ipatest.com"
yield "fake.ipatest.com"
diff --git a/ipalib/plugable.py b/ipalib/plugable.py
index 98a74dfa7..ffe4a11f1 100644
--- a/ipalib/plugable.py
+++ b/ipalib/plugable.py
@@ -692,32 +692,50 @@ class Registrar(DictProxy):
self.__registered.add(klass)
-class Environment(dict):
+class Environment(object):
+ def __init__(self):
+ object.__setattr__(self, '_Environment__map', {})
+
+ def __setattr__(self, name, value):
+ self[name] = value
+
+ def __getattr__(self, name):
+ return self[name]
+
+ def __delattr__(self, name):
+ del self[name]
+
def __getitem__(self, key):
- val = super(Environment, self).__getitem__(key)
+ val = self.__map[key]
if hasattr(val, 'get_value'):
return val.get_value()
else:
return val
def __setitem__(self, key, value):
- if key in self:
- super_value = super(Environment, self).__getitem__(key)
-
- if key in self and hasattr(super_value, 'set_value'):
- super_value.set_value(value)
- else:
- super(Environment, self).__setitem__(key, value)
+ if key in self or hasattr(self, key):
+ raise AttributeError('cannot overwrite %s.%s' %
+ (self.__class__.__name__, key)
+ )
+ self.__map[key] = value
+
+ def __delitem__(self, key):
+ raise AttributeError('read-only: cannot del %s.%s' %
+ (self.__class__.__name__, key)
+ )
- def __getattr__(self, name):
- return self[name]
+ def __contains__(self, key):
+ return key in self.__map
- def __setattr__(self, name, value):
- self[name] = value
+ def __iter__(self):
+ for key in self.__map:
+ yield key
- def update(self, d):
- assert isinstance(d, dict)
- for key, value in d.iteritems():
+ def update(self, new_vals, ignore_errors = False):
+ assert type(new_vals) == dict
+ for key, value in new_vals.iteritems():
+ if key in self and ignore_errors:
+ continue
self[key] = value
@@ -727,10 +745,10 @@ class API(DictProxy):
"""
__finalized = False
- def __init__(self, default_env, *allowed):
+ def __init__(self, *allowed):
self.__d = dict()
self.register = Registrar(*allowed)
- self.env = Environment(default_env)
+ self.env = Environment()
super(API, self).__init__(self.__d)
def finalize(self):
diff --git a/ipalib/tests/test_crud.py b/ipalib/tests/test_crud.py
index df85253b8..9355f237e 100644
--- a/ipalib/tests/test_crud.py
+++ b/ipalib/tests/test_crud.py
@@ -26,11 +26,11 @@ from ipalib import crud, frontend, plugable, config
def get_api():
api = plugable.API(
- config.default_environment(),
frontend.Object,
frontend.Method,
frontend.Property,
)
+ api.env.update(config.generate_env())
class user(frontend.Object):
takes_params = (
'givenname',
diff --git a/ipalib/tests/test_frontend.py b/ipalib/tests/test_frontend.py
index e3dd04fac..c70cc00d7 100644
--- a/ipalib/tests/test_frontend.py
+++ b/ipalib/tests/test_frontend.py
@@ -732,7 +732,8 @@ class test_Command(ClassChecker):
kw = dict(how_are='you', on_this='fine day?')
# Test in server context:
- api = plugable.API(dict(server_context=True), self.cls)
+ api = plugable.API(self.cls)
+ api.env.update(dict(server_context=True))
api.finalize()
o = my_cmd()
o.set_api(api)
@@ -741,7 +742,8 @@ class test_Command(ClassChecker):
assert o.run.im_func is my_cmd.execute.im_func
# Test in non-server context
- api = plugable.API(dict(server_context=False), self.cls)
+ api = plugable.API(self.cls)
+ api.env.update(dict(server_context=False))
api.finalize()
o = my_cmd()
o.set_api(api)
@@ -868,10 +870,10 @@ class test_Object(ClassChecker):
Test the `frontend.Object.primary_key` attribute.
"""
api = plugable.API(
- config.default_environment(),
frontend.Method,
frontend.Property,
)
+ api.env.update(config.generate_env())
api.finalize()
# Test with no primary keys:
@@ -923,12 +925,12 @@ class test_Object(ClassChecker):
Test the `frontend.Object.backend` attribute.
"""
api = plugable.API(
- config.default_environment(),
frontend.Object,
frontend.Method,
frontend.Property,
backend.Backend,
)
+ api.env.update(config.generate_env())
class ldap(backend.Backend):
whatever = 'It worked!'
api.register(ldap)
diff --git a/ipalib/tests/test_plugable.py b/ipalib/tests/test_plugable.py
index 9be6b343e..fd3c3c887 100644
--- a/ipalib/tests/test_plugable.py
+++ b/ipalib/tests/test_plugable.py
@@ -620,6 +620,84 @@ class test_NameSpace(ClassChecker):
'NameSpace(<%d members>, sort=%r)' % (cnt, sort)
+def test_Environment():
+ """
+ Tests the `plugable.Environment` class.
+ """
+ # This has to be the same as iter_cnt
+ control_cnt = 0
+ class prop_class:
+ def __init__(self, val):
+ self._val = val
+ def get_value(self):
+ return self._val
+
+ class iter_class(prop_class):
+ # Increment this for each time iter_class yields
+ iter_cnt = 0
+ def get_value(self):
+ for item in self._val:
+ self.__class__.iter_cnt += 1
+ yield item
+
+ # Tests for basic functionality
+ basic_tests = (
+ ('a', 1),
+ ('b', 'basic_foo'),
+ ('c', ('basic_bar', 'basic_baz')),
+ )
+ # Tests with prop classes
+ prop_tests = (
+ ('d', prop_class(2), 2),
+ ('e', prop_class('prop_foo'), 'prop_foo'),
+ ('f', prop_class(('prop_bar', 'prop_baz')), ('prop_bar', 'prop_baz')),
+ )
+ # Tests with iter classes
+ iter_tests = (
+ ('g', iter_class((3, 4, 5)), (3, 4, 5)),
+ ('h', iter_class(('iter_foo', 'iter_bar', 'iter_baz')),
+ ('iter_foo', 'iter_bar', 'iter_baz')
+ ),
+ )
+
+ # Set all the values
+ env = plugable.Environment()
+ for name, val in basic_tests:
+ env[name] = val
+ for name, val, dummy in prop_tests:
+ env[name] = val
+ for name, val, dummy in iter_tests:
+ env[name] = val
+
+ # Test if the values are correct
+ for name, val in basic_tests:
+ assert env[name] == val
+ for name, dummy, val in prop_tests:
+ assert env[name] == val
+ # Test if the get_value() function is called only when needed
+ for name, dummy, correct_values in iter_tests:
+ values_in_env = []
+ for val in env[name]:
+ control_cnt += 1
+ assert iter_class.iter_cnt == control_cnt
+ values_in_env.append(val)
+ assert tuple(values_in_env) == correct_values
+
+ # Test __setattr__()
+ env.spam = 'ham'
+ assert env.spam == 'ham'
+
+ # Test if we throw AttributeError exception when trying to overwrite
+ # existing value, or delete it
+ raises(AttributeError, setitem, env, 'a', 1)
+ raises(AttributeError, setattr, env, 'a', 1)
+ raises(AttributeError, delitem, env, 'a')
+ raises(AttributeError, delattr, env, 'a')
+ raises(AttributeError, plugable.Environment.update, env, dict(a=1000))
+ # This should be silently ignored
+ env.update(dict(a=1000), True)
+ assert env.a != 1000
+
def test_Registrar():
class Base1(object):
pass
@@ -722,6 +800,7 @@ def test_Registrar():
assert issubclass(klass, base)
+
def test_API():
assert issubclass(plugable.API, plugable.ReadOnly)
@@ -742,7 +821,7 @@ def test_API():
def method(self, n):
return n + 1
- api = plugable.API(dict(), base0, base1)
+ api = plugable.API(base0, base1)
r = api.register
assert isinstance(r, plugable.Registrar)
assert read_only(api, 'register') is r
@@ -800,7 +879,7 @@ def test_API():
# Test with base class that doesn't request a proxy
class NoProxy(plugable.Plugin):
__proxy__ = False
- api = plugable.API(dict(), NoProxy)
+ api = plugable.API(NoProxy)
class plugin0(NoProxy):
pass
api.register(plugin0)
diff --git a/ipalib/tests/tstutil.py b/ipalib/tests/tstutil.py
index 7586d08c5..743716a08 100644
--- a/ipalib/tests/tstutil.py
+++ b/ipalib/tests/tstutil.py
@@ -55,7 +55,7 @@ def raises(exception, callback, *args, **kw):
def getitem(obj, key):
"""
- Works like getattr but for dictionary interface. Uses this in combination
+ Works like getattr but for dictionary interface. Use this in combination
with raises() to test that, for example, KeyError is raised.
"""
return obj[key]
@@ -63,7 +63,7 @@ def getitem(obj, key):
def setitem(obj, key, value):
"""
- Works like setattr but for dictionary interface. Uses this in combination
+ Works like setattr but for dictionary interface. Use this in combination
with raises() to test that, for example, TypeError is raised.
"""
obj[key] = value
@@ -71,7 +71,7 @@ def setitem(obj, key, value):
def delitem(obj, key):
"""
- Works like delattr but for dictionary interface. Uses this in combination
+ Works like delattr but for dictionary interface. Use this in combination
with raises() to test that, for example, TypeError is raised.
"""
del obj[key]