[Zope3-checkins] CVS: Zope3/src/zope/schema - vocabulary.py:1.12

Fred L. Drake, Jr. fred@zope.com
Wed, 4 Jun 2003 14:09:37 -0400


Update of /cvs-repository/Zope3/src/zope/schema
In directory cvs.zope.org:/tmp/cvs-serv20979

Modified Files:
	vocabulary.py 
Log Message:
Refactored the SimpleVocabulary constructors to allow creating instances from
a sequence of terms.  Better support for specializing the vocabulary by
moving term creation to a new class method.


=== Zope3/src/zope/schema/vocabulary.py 1.11 => 1.12 ===
--- Zope3/src/zope/schema/vocabulary.py:1.11	Tue Jun  3 18:46:28 2003
+++ Zope3/src/zope/schema/vocabulary.py	Wed Jun  4 14:09:07 2003
@@ -140,7 +140,7 @@
 # simple vocabularies performing enumerated-like tasks
 
 class SimpleTerm:
-    """Simple tokenized term used by SimpleVocabulary"""
+    """Simple tokenized term used by SimpleVocabulary."""
 
     implements(ITokenizedTerm)
 
@@ -154,49 +154,71 @@
         self.token = str(token)
 
 class SimpleVocabulary(object):
-    """vocabulary that uses a list or tuple"""
+    """Vocabulary that works from a sequence of terms."""
 
     implements(IVocabulary, IVocabularyTokenized)
 
-    def __init__(self, data, *interfaces):
-        """Construct a vocabulary from a simple list. Values of the list become
-        both the tokens and values of the terms in the vocabulary. The order
-        of the values is preserved as the order of the terms in the vocabulary.
-        One or more interfaces may also be provided so that alternate widgets
-        may be bound without subclassing
+    def __init__(self, terms, *interfaces):
+        """Initialize the vocabulary given a list of terms.
+
+        The vocabulary keeps a reference to the list of terms passed
+        in; it should never be modified while the vocabulary is used.
+
+        One or more interfaces may also be provided so that alternate
+        widgets may be bound without subclassing.
         """
         self.by_value = {}
         self.by_token = {}
-        self._terms = []
-        for value in data:
-            term = SimpleTerm(value)
-            self.by_value[value] = term
+        self._terms = terms
+        for term in self._terms:
+            self.by_value[term.value] = term
             self.by_token[term.token] = term
-            self._terms.append(term)
-        assert len(self.by_value) == len(self.by_token), \
+        assert len(self.by_value) == len(self.by_token) == len(terms), \
                'Supplied vocabulary values resulted in duplicate term tokens'
         if interfaces:
             directlyProvides(self, *interfaces)
 
     def fromItems(cls, items, *interfaces):
         """Construct a vocabulary from a list of (token, value) pairs.
-        The order of the items is preserved as the order of the terms in the
-        vocabulary. One or more interfaces may also be provided so that
-        alternate widgets may be bound without subclassing
+
+        The order of the items is preserved as the order of the terms
+        in the vocabulary.  Terms are created by calling the class
+        method createTerm() with the pair (value, token).
+
+        One or more interfaces may also be provided so that alternate
+        widgets may be bound without subclassing.
         """
-        self = cls.__new__(cls, items, *interfaces)
-        self.by_value = {}
-        self.by_token = {}
-        self._terms = []
-        for token, value in items:
-            term = SimpleTerm(value, token)
-            self.by_value[value] = term
-            self.by_token[term.token] = term
-            self._terms.append(term)
-        assert len(self.by_value) == len(self.by_token), \
-               'Supplied vocabulary items resulted in duplicate term tokens'
-        return self
+        terms = [cls.createTerm((value, token)) for (token, value) in items]
+        return cls(terms, *interfaces)
     fromItems = classmethod(fromItems)
+
+    def fromValues(cls, values, *interfaces):
+        """Construct a vocabulary from a simple list.
+
+        Values of the list become both the tokens and values of the
+        terms in the vocabulary.  The order of the values is preserved
+        as the order of the terms in the vocabulary.  Tokens are
+        created by calling the class method createTerm() with the
+        value as the only parameter.
+
+        One or more interfaces may also be provided so that alternate
+        widgets may be bound without subclassing.
+        """
+        terms = [cls.createTerm(value) for value in values]
+        return cls(terms, *interfaces)
+    fromValues = classmethod(fromValues)
+
+    def createTerm(cls, data):
+        """Create a single term from data.
+
+        Subclasses may override this with a class method that creates
+        a term of the appropriate type from the single data argument.
+        """
+        if isinstance(data, tuple):
+            return SimpleTerm(*data)
+        else:
+            return SimpleTerm(data)
+    createTerm = classmethod(createTerm)
 
     def __contains__(self, value):
         return value in self.by_value