Index: src/zope/schema/tests/test_vocabulary.py =================================================================== --- src/zope/schema/tests/test_vocabulary.py (Revision 124238) +++ src/zope/schema/tests/test_vocabulary.py (Arbeitskopie) @@ -305,27 +305,10 @@ except ValueError as e: self.assertEqual(str(e), "term values must be unique: '1'") - def test_overriding_createTerm(self): - class MyTerm(object): - def __init__(self, value): - self.value = value - self.token = repr(value) - self.nextvalue = value + 1 - - class MyVocabulary(vocabulary.TreeVocabulary): - def createTerm(cls, token, value, title=None): - return MyTerm(value) - createTerm = classmethod(createTerm) - - vocab = MyVocabulary.fromDict( - {(1, 1):{}, (2, 2):{}, (3, 3):{ (4,4):{} }} ) - for term in vocab: - self.assertEqual(term.value + 1, term.nextvalue) - def test_recursive_methods(self): """Test the _createTermTree and _getPathToTreeNode methods """ - tree = vocabulary.TreeVocabulary._createTermTree({}, self.business_tree) + tree = vocabulary._createTermTree({}, self.business_tree) vocab = vocabulary.TreeVocabulary.fromDict(self.business_tree) term_path = vocab._getPathToTreeNode(tree, "infrastructure") Index: src/zope/schema/vocabulary.py =================================================================== --- src/zope/schema/vocabulary.py (Revision 124238) +++ src/zope/schema/vocabulary.py (Arbeitskopie) @@ -138,6 +138,19 @@ return len(self.by_value) + +def _createTermTree(tree, branch): + """ Helper function that creates a tree-like dict with ITokenizedTerm + objects as keys from a similar tree with tuples as keys. + + See fromDict for more details. + """ + for key in branch.keys(): + term = SimpleTerm(key[1], key[0], key[-1]) + tree[term] = {} + _createTermTree(tree[term], branch[key]) + return tree + @implementer(ITreeVocabulary) class TreeVocabulary(dict): """ Vocabulary that has a tree (i.e nested) structure. @@ -157,6 +170,7 @@ widgets may be bound without subclassing. """ self.update(terms) + self.path_index = {} self.by_value = self._flattenTree(terms, {}, 'value') self.by_token = self._flattenTree(terms, {}, 'token') @@ -172,19 +186,6 @@ return False @classmethod - def _createTermTree(cls, tree, branch): - """ Helper method that creates a tree-like dict with ITokenizedTerm - objects as keys from a similar tree with tuples as keys. - - See fromDict for more details. - """ - for key in branch.keys(): - term = cls.createTerm(key[1], key[0], key[-1]) - tree[term] = {} - cls._createTermTree(tree[term], branch[key]) - return tree - - @classmethod def fromDict(cls, _dict, *interfaces): """Constructs a vocabulary from a dictionary with tuples as keys. The tuples can have 2 or three values, i.e: @@ -207,17 +208,10 @@ One or more interfaces may also be provided so that alternate widgets may be bound without subclassing. """ - return cls(cls._createTermTree({}, _dict), *interfaces) - - @classmethod - def createTerm(cls, *args): - """Create a single term from data. - - Subclasses may override this with a class method that creates - a term of the appropriate type from the arguments. - """ - return SimpleTerm(*args) + tree = _createTermTree({}, _dict) + return cls(tree, *interfaces) + def _flattenTree(self, tree, _dict, attr): """A helper method to create a flat (non-nested) dictionary from a tree. @@ -239,6 +233,12 @@ _dict[attrval] = term self._flattenTree(tree[term], _dict, attr) + + # Add node to path index + if term.value not in self.path_index: + self.path_index[term.value] = self._getPathToTreeNode(self, + term.value) + return _dict def getTerm(self, value): @@ -270,7 +270,21 @@ path = [key.value] + path break return path + + + def _getPathToTreeNode(self, tree, node): + """Alternative slightly less greedy implementation""" + path = [] + for parent, child in tree.items(): + if node == parent.value: + return [node] + path = self._getPathToTreeNode(child, node) + if path: + path.insert(0, parent.value) + break + return path + def getTermPath(self, value): """Returns a list of strings representing the path from the root node to the node with the given value in the tree. @@ -278,6 +292,10 @@ Returns an empty string if no node has that value. """ return self._getPathToTreeNode(self, value) + + def getTermPath(self, value): + """Alternative implementation using a path index""" + return self.path_index.get(value, []) # registry code