diff --git a/ipalib/public.py b/ipalib/public.py index baae83e42..9467feaff 100644 --- a/ipalib/public.py +++ b/ipalib/public.py @@ -58,17 +58,24 @@ class opt(plugable.ReadOnly): def __get_rules(self): if self.__rules is None: - self.__rules = tuple(self.__rules_iter()) + rules = sorted( + self.__rules_iter(), + key=lambda f: getattr(f, '__name__'), + ) + object.__setattr__(self, '_opt__rules', tuple(rules)) return self.__rules rules = property(__get_rules) def __rules_iter(self): - for name in dir(self): + for name in dir(self.__class__): if name.startswith('_'): continue - attr = getattr(self, name) - if is_rule(attr): - yield attr + base_attr = getattr(self.__class__, name) + if is_rule(base_attr): + attr = getattr(self, name) + if is_rule(attr): + yield attr + def validate(self, value): pass @@ -77,7 +84,6 @@ class opt(plugable.ReadOnly): - class cmd(plugable.Plugin): __public__ = frozenset(( 'normalize', diff --git a/ipalib/tests/test_public.py b/ipalib/tests/test_public.py index ef2ded171..87d6d1042 100644 --- a/ipalib/tests/test_public.py +++ b/ipalib/tests/test_public.py @@ -68,10 +68,36 @@ class test_opt(): return public.opt def sub(self): + rule = public.rule class int_opt(self.cls()): type = int + @rule + def rule_a(self, value): + if value == 'a': + return 'cannot be a' + @rule + def rule_b(self, value): + if value == 'b': + return 'cannot be b' + @rule + def rule_c(self, value): + if value == 'c': + return 'cannot be c' return int_opt + def test_rules(self): + """ + Test the rules property. + """ + i = self.sub()() + def i_attr(l): + return getattr(i, 'rule_%s' % l) + letters = ('a', 'b', 'c') + rules = tuple(i_attr(l) for l in letters) + assert i.rules == rules + + + def test_class(self): cls = self.cls() assert issubclass(cls, plugable.ReadOnly)