Environment is now subclassed from object, rather then dict. Added tests for Environment and config.py

This commit is contained in:
Martin Nagy 2008-10-02 20:24:05 +02:00 committed by Jason Gerard DeRose
parent 6000b6b5c6
commit 149429f305
8 changed files with 151 additions and 50 deletions

View File

@ -61,7 +61,6 @@ import backend
import config
api = plugable.API(
config.default_environment(),
frontend.Command,
frontend.Object,
frontend.Method,

View File

@ -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()

View File

@ -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"

View File

@ -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 or hasattr(self, key):
raise AttributeError('cannot overwrite %s.%s' %
(self.__class__.__name__, key)
)
self.__map[key] = value
if key in self and hasattr(super_value, 'set_value'):
super_value.set_value(value)
else:
super(Environment, self).__setitem__(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):

View File

@ -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',

View File

@ -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)

View File

@ -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)

View File

@ -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]