mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Environment is now subclassed from object, rather then dict. Added tests for Environment and config.py
This commit is contained in:
parent
6000b6b5c6
commit
149429f305
@ -61,7 +61,6 @@ import backend
|
||||
import config
|
||||
|
||||
api = plugable.API(
|
||||
config.default_environment(),
|
||||
frontend.Command,
|
||||
frontend.Object,
|
||||
frontend.Method,
|
||||
|
@ -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()
|
||||
|
@ -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"
|
||||
|
@ -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):
|
||||
|
@ -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',
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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]
|
||||
|
Loading…
Reference in New Issue
Block a user