Changeset 4106

Show
Ignore:
Timestamp:
02/08/08 10:39:59 (6 months ago)
Author:
chrisz
Message:

Cleaned up the validators module. Removed old FormEncode patches that are not necessary any more. This should also fix #1705.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/1.0/turbogears/validators.py

    r3366 r4106  
    33This module also imports everything from formencode.validators, so all 
    44common validation routines are available here.""" 
    5  
    6 import pkg_resources 
    7 #XXX Remove in 1.0.3 when everyone has already upgraded FE 
    8 #    so we don't need to keep this in sync with setup.py 
    9 pkg_resources.require("FormEncode >= 0.7.1") 
    105 
    116import time 
    127import re 
    138from datetime import datetime 
    14 import cgi # FieldStorageUploadConverter 
    159import warnings 
    1610 
     
    2620from turbojson import jsonify 
    2721 
    28 from formencode import validators # Needed to disambiguate the Number validator... 
    29  
    30 import __builtin__ 
     22from formencode import validators # to disambiguate the Number validator... 
    3123 
    3224def _(s): return s # dummy 
    3325 
    34 Validator.gettextargs['domain'] = 'FormEncode' # FormEncode should call Tg's gettext \ 
    35                                                # function with domain = "FormEncode" 
     26# FormEncode should call TG's gettext function with domain = "FormEncode" 
     27Validator.gettextargs['domain'] = 'FormEncode' 
     28 
    3629 
    3730class TgFancyValidator(FancyValidator): 
    38     gettextargs = {'domain':'TurboGears'} 
     31    gettextargs = {'domain': 'TurboGears'} 
     32 
    3933 
    4034class Money(TgFancyValidator): 
     35    """Validate a monetary value with currency.""" 
    4136 
    4237    messages = { 
     
    5449 
    5550    def _to_python(self, value, state): 
    56         """ parse a string and returns a float or integer """ 
     51        """Parse a string and return a float or integer.""" 
    5752        try: 
    5853            return format.parse_decimal(value) 
     
    6156 
    6257    def _from_python(self, value, state): 
    63         """ returns a string using the correct grouping """ 
     58        """Return a string using the correct grouping.""" 
    6459        return format.format_currency(value) 
    6560 
    6661 
    6762class Number(TgFancyValidator): 
    68  
    69     def _to_python(self, value, state): 
    70         """ parse a string and returns a float or integer """ 
     63    """Validate a decimal number.""" 
     64 
     65    def _to_python(self, value, state): 
     66        """Parse a string and return a float or integer.""" 
    7167        if isinstance(value, basestring): 
    7268            try: 
     
    7773 
    7874    def _from_python(self, value, state): 
    79         """ returns a string using the correct grouping """ 
     75        """Return a string using the correct grouping.""" 
    8076        dec_places = util.find_precision(value) 
    8177        if dec_places > 0: 
     
    8682 
    8783class DateTimeConverter(TgFancyValidator): 
    88  
    89     """ 
    90     Converts Python date and datetime objects into string representation and back. 
    91     """ 
     84    """Convert between Python datetime objects and strings.""" 
     85 
    9286    messages = { 
    9387        'badFormat': _('Invalid datetime format'), 
     
    9589    } 
    9690 
    97     def __init__(self, format = "%Y/%m/%d %H:%M", allow_empty = None, 
     91    def __init__(self, format="%Y/%m/%d %H:%M", allow_empty=None, 
    9892                *args, **kwargs): 
    9993        if allow_empty is not None: 
     
    106100 
    107101    def _to_python(self, value, state): 
    108         """ parse a string and return a datetime object. """ 
     102        """Parse a string and return a datetime object.""" 
    109103        if value and isinstance(value, datetime): 
    110104            return value 
    111105        else: 
    112106            try: 
    113                 # DBR start 
    114107                format = self.format 
    115108                if callable(format): 
    116109                    format = format() 
    117110                tpl = time.strptime(value, format) 
    118                 # DBR end 
    119  
    120111            except ValueError: 
    121112                raise Invalid(self.message('badFormat', state), value, state) 
     
    126117 
    127118    def _from_python(self, value, state): 
     119        """Return a string representation of a datetime object.""" 
    128120        if not value: 
    129121            return None 
    130122        elif isinstance(value, datetime): 
    131123            # Python stdlib can only handle dates with year greater than 1900 
    132             # DBR start 
    133124            format = self.format 
    134125            if callable(format): 
     
    140131            else: 
    141132                return value.strftime(format) 
    142             # DBR end 
    143133        else: 
    144134            return value 
    145135 
    146 # formencode trunk contains UnicodeString implementation 
    147 # but it is different from ours and was broken at the time. 
    148 # remove this impl. when formencode.validators.UnicodeString will be identical to ours. 
    149 class UnicodeString(String): 
    150     encoding = 'utf-8' 
    151     messages = { 
    152         'badEncoding' : _("Invalid data or incorrect encoding"), 
    153     } 
    154     def __init__(self, inputEncoding=None, outputEncoding=None, **kw): 
    155         String.__init__(self, **kw) 
    156         self.inputEncoding = inputEncoding or self.encoding 
    157         self.outputEncoding = outputEncoding or self.encoding 
    158     def _to_python(self, value, state): 
    159         if value: 
    160             if isinstance(value, unicode): 
    161                 return value 
    162             if hasattr(value, '__unicode__'): 
    163                 return unicode(value) 
    164             try: 
    165                 return unicode(value, self.inputEncoding) 
    166             except UnicodeDecodeError: 
    167                 raise Invalid(self.message('badEncoding', state), value, state) 
    168         return u'' 
    169     def _from_python(self, value, state): 
    170         if hasattr(value, '__unicode__'): 
    171             value = unicode(value) 
    172         if isinstance(value, unicode): 
    173             return value.encode(self.outputEncoding) 
    174         return str(value) 
    175  
    176 # another formencode workaround, 
    177 # see #1464357 on FE bugtracker (http://tinyurl.com/lm9ae). 
    178 # Custom version of FieldStorage validator that does not break FE schema validator. 
    179 class FieldStorageUploadConverter(TgFancyValidator): 
    180     def to_python(self, value, state=None): 
    181         if isinstance(value, cgi.FieldStorage): 
    182             if value.filename: 
    183                 return value 
    184             raise Invalid('invalid', value, state) 
    185         else: 
    186             return value 
    187136 
    188137# For translated messages that are not wrapped in a Validator.messages 
     
    193142_ = lambda s: turbogears.i18n.gettext(s, domain='TurboGears') 
    194143 
     144 
    195145class MultipleSelection(ForEach): 
     146    """A default validator for SelectionFields with multiple selection.""" 
     147 
    196148    if_missing = NoDefault 
    197149    if_empty = [] 
     
    203155            raise Invalid(_("Please select at least a value"), value, state) 
    204156 
     157 
    205158class Schema(Schema): 
    206     """ A Schema validator """ 
     159    """Modified Schema validator for TurboGears.""" 
     160 
    207161    filter_extra_fields = True 
    208162    allow_extra_fields = True 
    209163    if_key_missing = None 
    210164 
    211     def from_python(self,value,state=None): 
     165    def from_python(self, value, state=None): 
    212166        # The Schema shouldn't do any from_python conversion because 
    213167        # adjust_value already takes care of that for all childs. 
    214168        return value 
    215169 
     170 
    216171class JSONValidator(TgFancyValidator): 
     172    """A validator for JSON format.""" 
    217173 
    218174    def _from_python(self, value, state): 
     
    222178        return simplejson.loads(value) 
    223179 
    224 _illegal_s = re.compile(r"((^|[^%])(%%)*%s)") 
     180 
     181# Auxiliary functions 
    225182 
    226183def _findall(text, substr): 
     
    236193    return sites 
    237194 
     195_illegal_s = re.compile(r"((^|[^%])(%%)*%s)") 
     196 
    238197def strftime_before1900(dt, fmt): 
     198    """strftime implementation supporting proleptic Gregorian dates before 1900. 
     199 
     200    @see: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/306860 
     201 
    239202    """ 
    240     A strftime implementation that supports proleptic Gregorian dates before 1900. 
    241  
    242     @see: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/306860 
    243     """ 
    244     import datetime 
    245203    if _illegal_s.search(fmt): 
    246204        raise TypeError("This strftime implementation does not handle %s") 
     
    253211    delta = 2000 - year 
    254212    off = 6*(delta // 100 + delta // 400) 
    255     year = year + off 
     213    year += off 
    256214 
    257215    # Move to around the year 2000 
  • branches/1.1/turbogears/validators.py

    r3367 r4106  
    33This module also imports everything from formencode.validators, so all 
    44common validation routines are available here.""" 
    5  
    6 import pkg_resources 
    7 #XXX Remove in 1.0.3 when everyone has already upgraded FE 
    8 #    so we don't need to keep this in sync with setup.py 
    9 pkg_resources.require("FormEncode >= 0.7.1") 
    105 
    116import time 
    127import re 
    138from datetime import datetime 
    14 import cgi # FieldStorageUploadConverter 
    159import warnings 
    1610 
     
    2620from turbojson import jsonify 
    2721 
    28 from formencode import validators # Needed to disambiguate the Number validator... 
    29  
    30 import __builtin__ 
     22from formencode import validators # to disambiguate the Number validator... 
    3123 
    3224def _(s): return s # dummy 
    3325 
    34 Validator.gettextargs['domain'] = 'FormEncode' # FormEncode should call Tg's gettext \ 
    35                                                # function with domain = "FormEncode" 
     26# FormEncode should call TG's gettext function with domain = "FormEncode" 
     27Validator.gettextargs['domain'] = 'FormEncode' 
     28 
    3629 
    3730class TgFancyValidator(FancyValidator): 
    38     gettextargs = {'domain':'TurboGears'} 
     31    gettextargs = {'domain': 'TurboGears'} 
     32 
    3933 
    4034class Money(TgFancyValidator): 
     35    """Validate a monetary value with currency.""" 
    4136 
    4237    messages = { 
     
    5449 
    5550    def _to_python(self, value, state): 
    56         """ parse a string and returns a float or integer """ 
     51        """Parse a string and return a float or integer.""" 
    5752        try: 
    5853            return format.parse_decimal(value) 
     
    6156 
    6257    def _from_python(self, value, state): 
    63         """ returns a string using the correct grouping """ 
     58        """Return a string using the correct grouping.""" 
    6459        return format.format_currency(value) 
    6560 
    6661 
    6762class Number(TgFancyValidator): 
    68  
    69     def _to_python(self, value, state): 
    70         """ parse a string and returns a float or integer """ 
     63    """Validate a decimal number.""" 
     64 
     65    def _to_python(self, value, state): 
     66        """Parse a string and return a float or integer.""" 
    7167        if isinstance(value, basestring): 
    7268            try: 
     
    7773 
    7874    def _from_python(self, value, state): 
    79         """ returns a string using the correct grouping """ 
     75        """Return a string using the correct grouping.""" 
    8076        dec_places = util.find_precision(value) 
    8177        if dec_places > 0: 
     
    8682 
    8783class DateTimeConverter(TgFancyValidator): 
    88  
    89     """ 
    90     Converts Python date and datetime objects into string representation and back. 
    91     """ 
     84    """Convert between Python datetime objects and strings.""" 
     85 
    9286    messages = { 
    9387        'badFormat': _('Invalid datetime format'), 
     
    9589    } 
    9690 
    97     def __init__(self, format = "%Y/%m/%d %H:%M", allow_empty = None, 
     91    def __init__(self, format="%Y/%m/%d %H:%M", allow_empty=None, 
    9892                *args, **kwargs): 
    9993        if allow_empty is not None: 
     
    106100 
    107101    def _to_python(self, value, state): 
    108         """ parse a string and return a datetime object. """ 
     102        """Parse a string and return a datetime object.""" 
    109103        if value and isinstance(value, datetime): 
    110104            return value 
    111105        else: 
    112106            try: 
    113                 # DBR start 
    114107                format = self.format 
    115108                if callable(format): 
    116109                    format = format() 
    117110                tpl = time.strptime(value, format) 
    118                 # DBR end 
    119  
    120111            except ValueError: 
    121112                raise Invalid(self.message('badFormat', state), value, state) 
     
    126117 
    127118    def _from_python(self, value, state): 
     119        """Return a string representation of a datetime object.""" 
    128120        if not value: 
    129121            return None 
    130122        elif isinstance(value, datetime): 
    131123            # Python stdlib can only handle dates with year greater than 1900 
    132             # DBR start 
    133124            format = self.format 
    134125            if callable(format): 
     
    140131            else: 
    141132                return value.strftime(format) 
    142             # DBR end 
    143133        else: 
    144134            return value 
    145135 
    146 # formencode trunk contains UnicodeString implementation 
    147 # but it is different from ours and was broken at the time. 
    148 # remove this impl. when formencode.validators.UnicodeString will be identical to ours. 
    149 class UnicodeString(String): 
    150     encoding = 'utf-8' 
    151     messages = { 
    152         'badEncoding' : _("Invalid data or incorrect encoding"), 
    153     } 
    154     def __init__(self, inputEncoding=None, outputEncoding=None, **kw): 
    155         String.__init__(self, **kw) 
    156         self.inputEncoding = inputEncoding or self.encoding 
    157         self.outputEncoding = outputEncoding or self.encoding 
    158     def _to_python(self, value, state): 
    159         if value: 
    160             if isinstance(value, unicode): 
    161                 return value 
    162             if hasattr(value, '__unicode__'): 
    163                 return unicode(value) 
    164             try: 
    165                 return unicode(value, self.inputEncoding) 
    166             except UnicodeDecodeError: 
    167                 raise Invalid(self.message('badEncoding', state), value, state) 
    168         return u'' 
    169     def _from_python(self, value, state): 
    170         if hasattr(value, '__unicode__'): 
    171             value = unicode(value) 
    172         if isinstance(value, unicode): 
    173             return value.encode(self.outputEncoding) 
    174         return str(value) 
    175  
    176 # another formencode workaround, 
    177 # see #1464357 on FE bugtracker (http://tinyurl.com/lm9ae). 
    178 # Custom version of FieldStorage validator that does not break FE schema validator. 
    179 class FieldStorageUploadConverter(TgFancyValidator): 
    180     def to_python(self, value, state=None): 
    181         if isinstance(value, cgi.FieldStorage): 
    182             if value.filename: 
    183                 return value 
    184             raise Invalid('invalid', value, state) 
    185         else: 
    186             return value 
    187136 
    188137# For translated messages that are not wrapped in a Validator.messages 
     
    193142_ = lambda s: turbogears.i18n.gettext(s, domain='TurboGears') 
    194143 
     144 
    195145class MultipleSelection(ForEach): 
     146    """A default validator for SelectionFields with multiple selection.""" 
     147 
    196148    if_missing = NoDefault 
    197149    if_empty = [] 
     
    203155            raise Invalid(_("Please select at least a value"), value, state) 
    204156 
     157 
    205158class Schema(Schema): 
    206     """ A Schema validator """ 
     159    """Modified Schema validator for TurboGears.""" 
     160 
    207161    filter_extra_fields = True 
    208162    allow_extra_fields = True 
    209163    if_key_missing = None 
    210164 
    211     def from_python(self,value,state=None): 
     165    def from_python(self, value, state=None): 
    212166        # The Schema shouldn't do any from_python conversion because 
    213167        # adjust_value already takes care of that for all childs. 
    214168        return value 
    215169 
     170 
    216171class JSONValidator(TgFancyValidator): 
     172    """A validator for JSON format.""" 
    217173 
    218174    def _from_python(self, value, state): 
     
    222178        return simplejson.loads(value) 
    223179 
    224 _illegal_s = re.compile(r"((^|[^%])(%%)*%s)") 
     180 
     181# Auxiliary functions 
    225182 
    226183def _findall(text, substr): 
     
    236193    return sites 
    237194 
     195_illegal_s = re.compile(r"((^|[^%])(%%)*%s)") 
     196 
    238197def strftime_before1900(dt, fmt): 
     198    """strftime implementation supporting proleptic Gregorian dates before 1900. 
     199 
     200    @see: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/306860 
     201 
    239202    """ 
    240     A strftime implementation that supports proleptic Gregorian dates before 1900. 
    241  
    242     @see: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/306860 
    243     """ 
    244     import datetime 
    245203    if _illegal_s.search(fmt): 
    246204        raise TypeError("This strftime implementation does not handle %s") 
     
    253211    delta = 2000 - year 
    254212    off = 6*(delta // 100 + delta // 400) 
    255     year = year + off 
     213    year += off 
    256214 
    257215    # Move to around the year 2000