Index: /waeup/branches/ulif-importers/src/waeup/utils/converters.py
===================================================================
--- /waeup/branches/ulif-importers/src/waeup/utils/converters.py	(revision 4833)
+++ /waeup/branches/ulif-importers/src/waeup/utils/converters.py	(revision 4834)
@@ -10,4 +10,7 @@
 from zope.schema.interfaces import IBool, IText, IInt, IChoice
 from waeup.interfaces import ISchemaTypeConverter
+
+# If a string has this value, it is considered as 'missing_value' or None.
+NONE_STRING_VALUE = ''
 
 class Converter(grok.Adapter):
@@ -32,4 +35,6 @@
         """
         result = None
+        if string is NONE_STRING_VALUE:
+            string = None
         if string is None:
             if self.context.required is True:
@@ -54,8 +59,12 @@
 
 class BoolConverter(Converter):
+    """A converter for zope.schema.Bool fields.
+    """
     grok.context(IBool)
     grok.provides(ISchemaTypeConverter)
 
     def _convertValueFromString(self, string):
+        if string is NONE_STRING_VALUE:
+            string = None
         if string is None:
             return None
@@ -72,4 +81,6 @@
     
 class TextConverter(Converter):
+    """A converter for zope.schema.interfaces.IText fields.
+    """
     grok.context(IText)
     grok.provides(ISchemaTypeConverter)
@@ -79,4 +90,6 @@
 
 class IntConverter(Converter):
+    """A converter for zope.schema.Int fields.
+    """
     grok.context(IInt)
     grok.provides(ISchemaTypeConverter)
@@ -86,16 +99,37 @@
 
 class ChoiceConverter(Converter):
+    """A converter for zope.schema.Choice fields.
+    """
     grok.context(IChoice)
     grok.provides(ISchemaTypeConverter)
 
+    tokens = None
+    values = None
+    
     def __init__(self, context):
         self.context = context
-        try:
-            self.terms = getMultiAdapter(
-                (self.context.source, TestRequest()), ITerms)
-        except:
-            self.terms = None
+        if not hasattr(self.context.source, 'factory'):
+            try:
+                self.terms = getMultiAdapter(
+                    (self.context.source, TestRequest()), ITerms)
+            except:
+                self.terms = None
+
+            return
+        if not hasattr(self.context.source.factory, 'getToken'):
+            return
+        # For expensive token/key lookups we create a 'cache'
+        # here. This speeds up mass operations with many conversions
+        # by factor 10 or more.
+        
+        # Mapping token -> value
+        self.tokens = dict([(self.context.source.factory.getToken(x), x)
+                            for x in self.context.source.factory.getValues()])
+        # Mapping value -> token
+        self.values = dict([(y,x) for x,y in self.tokens.items()])
 
     def _convertValueFromString(self, string):
+        if self.tokens is not None:
+            return self.tokens[string]
         if self.terms is not None:
             return self.terms.getValue(string)
@@ -103,5 +137,29 @@
 
     def _convertValueToString(self, value):
+        if self.values is not None:
+            return self.values[value]
         if self.terms is not None:
             return self.terms.getTerm(value).token
         return str(value)
+
+    def fromString(self, string=None, strict=False):
+        """Convert ``string`` to value according to assigned field type.
+
+        We change the default for ``strict``: this disables extra
+        validation checks for Choice fields and saves lots of time. If
+        a string/value is out of allowed range we get a value or key
+        error anyway.
+        """
+        return super(ChoiceConverter, self).fromString(string=string,
+                                                       strict=strict)
+
+    def toString(self, value, strict=False):
+        """Convert ``value`` to string according to assigned field type.
+
+        We change the default for ``strict``: this disables extra
+        validation checks for Choice fields and saves lots of time. If
+        a string/value is out of allowed range we get a value or key
+        error anyway.
+        """
+        return super(ChoiceConverter, self).toString(value=value,
+                                                     strict=strict)
