Ignore:
Timestamp:
29 Jul 2010, 08:07:57 (14 years ago)
Author:
uli
Message:

Merge changes from ulif-fasttables back into trunk.

Location:
main/waeup.sirp/trunk/src/waeup/sirp/utils
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.sirp/trunk/src/waeup/sirp/utils/converters.py

    r4920 r5328  
    11"""Converters for zope.schema-based datatypes.
    22"""
     3import datetime
    34import grok
    45from zope.component import getMultiAdapter
     
    89except ImportError:
    910    from zope.browser.interfaces import ITerms
    10 from zope.schema.interfaces import IBool, IText, IInt, IChoice
     11from zope.schema.interfaces import IBool, IText, IInt, IChoice, IDate
    1112from waeup.sirp.interfaces import ISchemaTypeConverter
    1213
     
    5253
    5354    def toString(self, value, strict=True):
     55        """Convert given `value` to string according to assigned field type.
     56        """
    5457        if strict:
    5558            self.context.validate(value)
     
    131134    def _convertValueFromString(self, string):
    132135        if self.tokens is not None:
    133             return self.tokens[string]
     136            result = None
     137            try:
     138                result = self.tokens[string]
     139            except KeyError:
     140                # Be gentle...
     141                try:
     142                    result = self.tokens[string.lower()]
     143                    return result
     144                except KeyError:
     145                    tokenlist = (','.join(self.tokens[:2]))
     146                    raise ValueError(
     147                        'The token %s is not valid. Use one of %s, ...' % (
     148                            string, tokenlist))
     149            return result
    134150        if self.terms is not None:
    135151            return self.terms.getValue(string)
    136         return self.context.source.getTermByToken(string).value
     152        result = self.context.source.getTermByToken(string).value
     153        return result
    137154
    138155    def _convertValueToString(self, value):
     
    164181        return super(ChoiceConverter, self).toString(value=value,
    165182                                                     strict=strict)
     183
     184class DateConverter(Converter):
     185    """A converter for zope.schema.IDate fields.
     186
     187    Converts date to string and vice versa. Stringified dates are
     188    expected in format ``YYYY-MM-DD``.
     189
     190    To support at least some other formats, we accept for conversion
     191    from string also the following formats:
     192
     193    * ``YYYY/MM/DD``
     194   
     195    * ``DD/MM/YYYY``
     196   
     197    * ``D/M/YYYY``
     198
     199    * ``DD.MM.YYYY``
     200
     201    * ``D.M.YYYY``
     202
     203    When converting to strings, always 'YYYY-MM-DD' is returned.
     204
     205    For convenience, when converting from strings also string data
     206    separated by space is stripped before processing. Therefore
     207    strings like '1990-04-01 12:12:01 GMT +1' will also work.
     208    """
     209    grok.context(IDate)
     210    grok.provides(ISchemaTypeConverter)
     211
     212    #: List of supported date formats in `strftime()` notation.
     213    formats = ['%Y-%m-%d', '%Y/%m/%d' , '%d/%m/%Y', '%D/%M/%Y',
     214               '%d.%m.%Y', '%D.%M.%Y']
     215   
     216    def _convertValueFromString(self, string):
     217        orig_string = string
     218        if string is NONE_STRING_VALUE:
     219            string = None
     220        if string is None:
     221            return None
     222        value = None
     223        if ' ' in string:
     224            string = string.split(' ')[0]
     225        for format in self.formats:
     226            try:
     227                value = datetime.datetime.strptime(string, format)
     228                break
     229            except ValueError:
     230                pass
     231        if value is None:
     232            raise ValueError(
     233                'Cannot convert to date: %s. Use YYYY-MM-DD.' %
     234                orig_string)
     235        value = value.date()
     236        return value
     237
     238    def _convertValueToString(self, value):
     239        return datetime.date.strftime(value, '%Y-%m-%d')
  • main/waeup.sirp/trunk/src/waeup/sirp/utils/converters.txt

    r5140 r5328  
    267267       validation checks are disabled with this converter. This speeds
    268268       up things as expensive lookups are avoided.
     269
     270
     271:class:`DateConverter`
     272----------------------
     273
     274.. autoclass:: waeup.sirp.utils.converters.DateConverter
     275   :members:
     276   :inherited-members:
    269277
    270278
     
    682690
    683691A more complex (but still realistic example) for conversion of
    684 :mode:`zope.schema.Choice` fields follows. Here we have a special kind
     692:mod:`zope.schema.Choice` fields follows. Here we have a special kind
    685693of object, the `Cave` class, and get their `name` attribute as token.
    686694
     
    739747    >>> converter.toString(obj2)
    740748    'Fred'
     749
     750Date field converters
     751---------------------
     752
     753We create a field that also implements ``IDate``, a regular
     754``Date`` field:
     755
     756    >>> from zope.schema import Date
     757    >>> from datetime import date
     758    >>> field = Date(title=u'Some date',
     759    ...             default=date(2010, 4, 1),
     760    ...             required=True)
     761
     762Now we can get a converter for this field by explicitly creating a
     763:class:`IntConverter` instance:
     764
     765    >>> from waeup.sirp.utils.converters import DateConverter
     766    >>> converter = DateConverter(field)
     767
     768Or we can just grab a registered adapter:
     769
     770    >>> from waeup.sirp.interfaces import ISchemaTypeConverter
     771    >>> converter = ISchemaTypeConverter(field)
     772
     773This will select the correct converter for us automatically.
     774
     775    >>> converter
     776    <waeup.sirp.utils.converters.DateConverter object at 0x...>
     777
     778Now we can convert strings to this type:
     779
     780    >>> converter.fromString('2007-04-23')
     781    datetime.date(2007, 4, 23)
     782
     783And back:
     784
     785    >>> converter.toString(date(2007,4,23))
     786    '2007-04-23'
     787
     788As string input we also accept 'DD/MM/YYYY':
     789
     790    >>> converter.fromString('13/05/1945')
     791    datetime.date(1945, 5, 13)
     792
     793and some more bizarre formats:
     794
     795    >>> converter.fromString('1945/05/13')
     796    datetime.date(1945, 5, 13)
     797
     798    >>> converter.fromString('1945/05/13 12:12:34 GMT+1')
     799    datetime.date(1945, 5, 13)
     800
     801    >>> converter.fromString('1945/5/6')
     802    datetime.date(1945, 5, 6)
     803
     804    >>> converter.fromString('06.05.1945')
     805    datetime.date(1945, 5, 6)
     806
     807    >>> converter.fromString('6.5.1945')
     808    datetime.date(1945, 5, 6)
     809
     810while other date formats will mean trouble:
     811
     812    >>> converter.fromString('first of July 1960')
     813    Traceback (most recent call last):
     814    ...
     815    ValueError: Cannot convert to date: first of July 1960. Use YYYY-MM-DD.
     816
     817Okay, not very surprising. But the field definitions can help also
     818deliver values, if the given value is missing:
     819
     820    >>> converter.fromString(None)
     821    datetime.date(2010, 4, 1)
     822
     823``None`` is not an acceptable value for fields which are required but
     824provide no default:
     825
     826    >>> field = Date(title=u'Some Title',
     827    ...             required=True)
     828    >>> converter = ISchemaTypeConverter(field)
     829    >>> converter.fromString(None)
     830    Traceback (most recent call last):
     831    ...
     832    RequiredMissing
     833
     834If we want to avoid this type of exception (and risk non-applicable
     835data to be stored), we can use the ``strict`` parameter of
     836``fromString()``:
     837
     838    >>> converter.fromString(None, strict=False) is None
     839    True
     840
     841The same for the inverse operation:
     842
     843    >>> converter.toString(None)
     844    Traceback (most recent call last):
     845    ...
     846    RequiredMissing
     847    >>> converter.toString(None, strict=False) is None
     848    True
     849
     850
     851If a field is not required, we will get the ``missing_value`` type in
     852same case:
     853
     854    >>> field = Date(title=u'Some Title',
     855    ...             required=False)
     856    >>> converter = ISchemaTypeConverter(field)
     857    >>> converter.fromString(None) is None
     858    True
     859
     860    >>> converter.toString(None) is None
     861    True
Note: See TracChangeset for help on using the changeset viewer.