def _apply(self, value): value = self._filter(value, Type(text_type)) if self._has_errors: return None # http://stackoverflow.com/a/4017219 if self.ipv4: try: socket.inet_pton(socket.AF_INET, value) except socket.error: pass else: return value if self.ipv6: try: n = socket.inet_pton(socket.AF_INET6, value) except socket.error: pass else: # Convert the binary value back into a string # representation so that the end result is # normalized. # https://en.wikipedia.org/wiki/IPv6_address#Presentation return socket.inet_ntop(socket.AF_INET6, n) # If we get here, we failed the above checks (or the Filter is # configured not to allow anything through). return self._invalid_value( value=value, reason=self.CODE_INVALID, template_vars={'ip_type': self.ip_type}, )
def _apply(self, value): # Lazy-load dependencies to reduce memory usage when this # filter is not used in a project. from moneyed import ( Currency as CurrencyType, CurrencyDoesNotExist, get_currency, ) value = self._filter(value, Type(string_types + (CurrencyType, ))) if self._has_errors: return None if isinstance(value, CurrencyType): return value try: # # Note that ``get_currency`` explicitly casts the incoming # code to ASCII, so it is possible to get a # UnicodeDecodeError here (e.g., the incoming value is # a currency symbol instead of an ISO currency code). # # To keep things simple for the end user, we will treat # this error the same as if the incoming value was a non- # matching ASCII value. # return get_currency(code=value.upper()) except (CurrencyDoesNotExist, UnicodeDecodeError): return self._invalid_value(value, self.CODE_INVALID, exc_info=True)
def _apply(self, value): allowed_types = (str, int, float, DecimalType,) if self.allow_tuples: # Python's Decimal type supports both tuples and lists. # :py:meth:`decimal.Decimal.__init__` allowed_types += (list, tuple,) value = self._filter(value, Type(allowed_types)) if self._has_errors: return value try: d = DecimalType(value) except (InvalidOperation, TypeError, ValueError): return self._invalid_value(value, self.CODE_INVALID, exc_info=True) # Decimal's constructor also accepts values such as 'NaN' or # '+Inf', which aren't valid in this context. # :see: decimal.Decimal._parser if not d.is_finite(): return self._invalid_value( value=value, reason=self.CODE_NON_FINITE, exc_info=True, ) if self.max_precision is not None: d = d.quantize(self.max_precision) return d
def _apply(self, value): value = self._filter(value, Type((str, UUID,))) # type: typing.Union[str, UUID] if self._has_errors: return None try: uuid = ( value if isinstance(value, UUID) else UUID(hex=value) ) except ValueError: return self._invalid_value(value, self.CODE_INVALID, exc_info=True) else: if self.version not in (None, uuid.version): return self._invalid_value( value=str(uuid), reason=self.CODE_WRONG_VERSION, context={ 'expected': self.version, 'incoming': uuid.version, }, ) return uuid
def _apply(self, value): value = self._filter(value, Type(Sized)) if self._has_errors: return None if len(value) > self.length: return self._invalid_value( value = value, reason = self.CODE_TOO_LONG, template_vars = { 'expected': self.length, }, ) elif len(value) < self.length: return self._invalid_value( value = value, reason = self.CODE_TOO_SHORT, template_vars = { 'expected': self.length, }, ) return value
def _apply(self, value): value = self._filter(value, Type(str)) # type: str if self._has_errors: return None return value.casefold()
def _apply(self, value): # Lazy-load dependencies to reduce memory usage when this # filter is not used in a project. from iso3166 import ( countries_by_alpha2, countries_by_alpha3, Country as CountryType, ) value = self._filter(value, Type(string_types + (CountryType, ))) if self._has_errors: return None if isinstance(value, CountryType): return value search_functions = { 2: countries_by_alpha2, 3: countries_by_alpha3, } try: return search_functions[len(value)][value.upper()] except KeyError: return self._invalid_value(value, self.CODE_INVALID, exc_info=True)
def _apply(self, value): # Lazy-load dependencies to reduce memory usage when this # filter is not used in a project. from language_tags import tags from language_tags.Tag import Tag value = self._filter(value, Type(string_types + (Tag, ))) if self._has_errors: return None if isinstance(value, Tag): return value tag = tags.tag(value) if not tag.valid: return self._invalid_value( value=value, reason=self.CODE_INVALID, context={ 'parse_errors': [(error.code, error.message) for error in tag.errors], }, ) return tag
def _apply(self, value): value = self._filter(value, Type(Mapping)) # type: Mapping if self._has_errors: return None return self.result_type(self.iter(value))
def _apply(self, value): value = self._filter(value, Type(Iterable)) # type: Iterable if self._has_errors: return None result_type = (self.mapping_result_type if isinstance(value, Mapping) else self.sequence_result_type) return result_type(self.iter(value))
def _apply(self, value): value = self._filter(value, Type(Iterable)) if self._has_errors: return None if isinstance(value, bytearray): return value if isinstance(value, binary_type): return bytearray(value) if isinstance(value, text_type): try: return bytearray(value, encoding=self.encoding) except UnicodeEncodeError: return self._invalid_value( value = value, reason = self.CODE_BAD_ENCODING, template_vars = { 'encoding': self.encoding, }, ) from filters.complex import FilterRepeater filtered = self._filter(value, FilterRepeater( # Only allow ints and booleans. Type(int) # Convert booleans to int (Min and Max require an # exact type match). | Int # Min value for each byte is 2^0-1. | Min(0) # Max value for each byte is 2^8-1. | Max(255) )) if self._has_errors: return None return bytearray(filtered)
def _apply(self, value): value = self._filter(value, Type(str)) # type: str if self._has_errors: return None try: # :see: http://stackoverflow.com/a/6921760 return self.decoder(value, object_pairs_hook=OrderedDict) except ValueError: return self._invalid_value(value, self.CODE_INVALID, exc_info=True)
def _apply(self, value): value = self._filter(value, Type(str)) # type: str if self._has_errors: return None if self.leading: value = self.leading.sub('', value) if self.trailing: value = self.trailing.sub('', value) return value
def _apply(self, value): """ :return: Returns bytes, truncated to the correct length. Note: Might be a bit shorter than the max length, to avoid orphaning a multibyte sequence. """ value = self._filter( value=value, filter_chain=( Type((bytes, str,)) | Unicode(encoding=self.encoding) ), ) # type: str if self._has_errors: return None str_value = value.encode(self.encoding) if len(str_value) > self.max_bytes: replacement = ( self.truncate_string( # Ensure that we convert back to unicode before # adding the prefix, just in case `self.encoding` # indicates a codec that uses a BOM. value=self.prefix + value, max_bytes=self.max_bytes, encoding=self.encoding, ) if self.truncate else None ) return self._invalid_value( value=value, reason=self.CODE_TOO_LONG, replacement=replacement, context={ 'encoding': self.encoding, 'max_bytes': self.max_bytes, 'prefix': self.prefix, 'truncate': self.truncate, }, ) return str_value
def _apply(self, value): value = self._filter(value, Type(bytes)) # type: bytes if self._has_errors: return None # Strip out whitespace. # Technically, whitespace is not part of the Base64 alphabet, # but virtually every implementation allows it. value = self.whitespace_re.sub(b'', value) # Check for invalid characters. # Note that Python 3's b64decode does this for us, but we also # have to support Python 2. # https://docs.python.org/3/library/base64.html#base64.b64decode if not self.base64_re.match(value): return self._invalid_value( value=value, reason=self.CODE_INVALID, ) # Check to see if we are working with a URL-safe dialect. # https://en.wikipedia.org/wiki/Base64#URL_applications if (b'_' in value) or (b'-' in value): # You can't mix dialects, silly! if (b'+' in value) or (b'/' in value): return self._invalid_value( value=value, reason=self.CODE_INVALID, ) url_safe = True else: url_safe = False # Normalize padding. # http://stackoverflow.com/a/9807138/ value = value.rstrip(b'=') value += (b'=' * (4 - (len(value) % 4))) try: return ( urlsafe_b64decode(value) if url_safe else standard_b64decode(value) ) except TypeError: return self._invalid_value(value, self.CODE_INVALID, exc_info=True)
def _apply(self, value): # noinspection PyTypeChecker value = self._filter(value, Type((Iterable, Mapping))) if self._has_errors: return None if not isinstance(value, self.type): if isinstance(value, Mapping): # Check that the incoming value has exactly the right # keys. # noinspection PyProtectedMember value = self._filter( value, FilterMapper( dict.fromkeys(self.type._fields), allow_extra_keys=False, allow_missing_keys=False, )) if self._has_errors: return None value = self.type(**value) else: # Check that the incoming value has exactly the right # number of values. # noinspection PyProtectedMember value = self._filter(value, Length(len(self.type._fields))) if self._has_errors: return None value = self.type(*value) # At this point, ``value`` is an instance of :py:attr:`type`. # Now we just need to figure out whether additional filtering is # necessary. if self.filter_mapper: # noinspection PyProtectedMember filtered = self._filter(value._asdict(), self.filter_mapper) if self._has_errors: return None return self.type(**filtered) else: return value
def _apply(self, value): value = self._filter(value, Type(text_type)) # type: Text if self._has_errors: return None # In Python 3, case folding is supported natively. # In Python 2, this is the best we can do. # https://docs.python.org/3/library/stdtypes.html#str.casefold if PY3: # noinspection PyUnresolvedReferences return value.casefold() else: # noinspection PyUnresolvedReferences from py2casefold import casefold return casefold(value)
def _apply(self, value): value = self._filter(value, Type(text_type)) if self._has_errors: return None matches = [match.group(0) for match in self.regex.finditer(value)] if not matches: return self._invalid_value( value=value, reason=self.CODE_INVALID, template_vars={ 'pattern': self.regex.pattern, }, ) return matches
def _apply(self, value): value = self._filter(value, Type(str)) # type: str if self._has_errors: return None split = self.regex.split(value) if self.keys: # The split value can have at most as many items as # ``self.keys``. split = self._filter(split, MaxLength(len(self.keys))) if self._has_errors: return None return OrderedDict(zip_longest(self.keys, split)) else: return split