Пример #1
0
    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},
        )
Пример #2
0
    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)
Пример #3
0
    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
Пример #4
0
    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
Пример #5
0
    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
Пример #6
0
    def _apply(self, value):
        value = self._filter(value, Type(str))  # type: str

        if self._has_errors:
            return None

        return value.casefold()
Пример #7
0
    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)
Пример #8
0
    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
Пример #9
0
    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))
Пример #10
0
    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))
Пример #11
0
    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)
Пример #12
0
    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)
Пример #13
0
    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
Пример #14
0
    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
Пример #15
0
    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)
Пример #16
0
    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
Пример #17
0
    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)
Пример #18
0
    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
Пример #19
0
    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