Example #1
0
    def __init__(self, fieldName, isAllowedToBeEmpty, length, rule, dataFormat):
        super(ChoiceFieldFormat, self).__init__(fieldName, isAllowedToBeEmpty, length, rule, dataFormat, emptyValue="")
        self.choices = []

        # Split rule into tokens, ignoring white space.
        tokens = _tools.tokenizeWithoutSpace(rule)

        # Extract choices from rule tokens.
        previousToky = None
        toky = tokens.next()
        while not _tools.isEofToken(toky):
            if _tools.isCommaToken(toky):
                # Handle comma after comma without choice.
                if previousToky:
                    previousTokyText = previousToky[1]
                else:
                    previousTokyText = None
                raise FieldSyntaxError(u"choice value must precede a comma (,) but found: %r" % previousTokyText)
            choice = _tools.tokenText(toky)
            if not choice:
                raise FieldSyntaxError(
                    u"choice field must be allowed to be empty instead of containing an empty choice"
                )
            self.choices.append(choice)
            toky = tokens.next()
            if not _tools.isEofToken(toky):
                if not _tools.isCommaToken(toky):
                    raise FieldSyntaxError(u"comma (,) must follow choice value %r but found: %r" % (choice, toky[1]))
                # Process next choice after comma.
                toky = tokens.next()
                if _tools.isEofToken(toky):
                    raise FieldSyntaxError(u"trailing comma (,) must be removed")
        if not self.isAllowedToBeEmpty and not self.choices:
            raise FieldSyntaxError(u"choice field without any choices must be allowed to be empty")
Example #2
0
    def __init__(self, description, rule, availableFieldNames, location=None):
        super(IsUniqueCheck, self).__init__(description, rule, availableFieldNames, location)

        self.fieldNamesToCheck = []

        # Extract field names to check from rule.
        ruleReadLine = StringIO.StringIO(rule).readline
        toky = tokenize.generate_tokens(ruleReadLine)
        afterComma = True
        nextToken = toky.next()
        uniqueFieldNames = set()
        while not _tools.isEofToken(nextToken):
            tokenType = nextToken[0]
            tokenValue = nextToken[1]
            if afterComma:
                if tokenType != tokenize.NAME:
                    raise CheckSyntaxError(u"field name must contain only ASCII letters, numbers and underscores (_) "
                                           + "but found: %r [token type=%r]" % (tokenValue, tokenType))
                try:
                    fields.getFieldNameIndex(tokenValue, availableFieldNames)
                    if tokenValue in uniqueFieldNames:
                        raise CheckSyntaxError(u"duplicate field name for unique check must be removed: %s" % tokenValue)
                    uniqueFieldNames.add(tokenValue)
                except fields.FieldLookupError, error:
                    raise CheckSyntaxError(unicode(error))
                self.fieldNamesToCheck.append(tokenValue)
            elif not _tools.isCommaToken(nextToken):
                raise CheckSyntaxError(u"after field name a comma (,) must follow but found: %r" % (tokenValue))
Example #3
0
    def __init__(self, fieldName, isAllowedToBeEmpty, length, rule,
                 dataFormat):
        super(ChoiceFieldFormat, self).__init__(fieldName,
                                                isAllowedToBeEmpty,
                                                length,
                                                rule,
                                                dataFormat,
                                                emptyValue="")
        self.choices = []

        # Split rule into tokens, ignoring white space.
        tokens = _tools.tokenizeWithoutSpace(rule)

        # Extract choices from rule tokens.
        previousToky = None
        toky = tokens.next()
        while not _tools.isEofToken(toky):
            if _tools.isCommaToken(toky):
                # Handle comma after comma without choice.
                if previousToky:
                    previousTokyText = previousToky[1]
                else:
                    previousTokyText = None
                raise FieldSyntaxError(
                    u"choice value must precede a comma (,) but found: %r" %
                    previousTokyText)
            choice = _tools.tokenText(toky)
            if not choice:
                raise FieldSyntaxError(
                    u"choice field must be allowed to be empty instead of containing an empty choice"
                )
            self.choices.append(choice)
            toky = tokens.next()
            if not _tools.isEofToken(toky):
                if not _tools.isCommaToken(toky):
                    raise FieldSyntaxError(
                        u"comma (,) must follow choice value %r but found: %r"
                        % (choice, toky[1]))
                # Process next choice after comma.
                toky = tokens.next()
                if _tools.isEofToken(toky):
                    raise FieldSyntaxError(
                        u"trailing comma (,) must be removed")
        if not self.isAllowedToBeEmpty and not self.choices:
            raise FieldSyntaxError(
                u"choice field without any choices must be allowed to be empty"
            )
Example #4
0
    def __init__(self, text, default=None):
        """
        Setup a range as specified by ``text``.

        ``text`` must be of the form "lower:upper" or "limit". In case ``text`` is empty (""), any
        value will be accepted by `validate()`. For example, "1:40" accepts values between 1
        and 40.

        ``default`` is an alternative text to use in case ``text`` is ``None`` or empty.
        """
        assert default is None or default.strip(), u"default=%r" % default

        # Find out if a `text` has been specified and if not, use optional `default` instead.
        hasText = (text is not None) and text.strip()
        if not hasText and default is not None:
            text = default
            hasText = True

        if not hasText:
            # Use empty ranges.
            self._description = None
            self._items = None
        else:
            self._description = text
            self._items = []
            # TODO: Consolidate code with `DelimitedDataFormat._validatedCharacter()`.
            tokens = tokenize.generate_tokens(StringIO.StringIO(text).readline)
            endReached = False
            while not endReached:
                lower = None
                upper = None
                colonFound = False
                afterHyphen = False
                nextToken = tokens.next()
                while not _tools.isEofToken(nextToken) and not _tools.isCommaToken(nextToken):
                    nextType = nextToken[0]
                    nextValue = nextToken[1]
                    if nextType in (token.NAME, token.NUMBER, token.STRING):
                        if nextType == token.NUMBER:
                            try:
                                if nextValue[:2].lower() == "0x":
                                    nextValue = nextValue[2:]
                                    base = 16
                                else:
                                    base = 10
                                longValue = long(nextValue, base)
                            except ValueError:
                                raise RangeSyntaxError(u"number must be an integer but is: %r" % nextValue)
                            if afterHyphen:
                                longValue = - 1 * longValue
                                afterHyphen = False
                        elif nextType == token.NAME:
                            try:
                                longValue = tools.SYMBOLIC_NAMES_MAP[nextValue.lower()]
                            except KeyError:
                                validSymbols = _tools.humanReadableList(sorted(tools.SYMBOLIC_NAMES_MAP.keys()))
                                raise RangeSyntaxError(u"symbolic name %r must be one of: %s" % (nextValue, validSymbols))
                        elif nextType == token.STRING:
                            if len(nextValue) != 3:
                                raise RangeSyntaxError(u"text for range must contain a single character but is: %r" % nextValue)
                            leftQuote = nextValue[0]
                            rightQuote = nextValue[2]
                            assert leftQuote in "\"\'", u"leftQuote=%r" % leftQuote
                            assert rightQuote in "\"\'", u"rightQuote=%r" % rightQuote
                            longValue = ord(nextValue[1])
                        if colonFound:
                            if upper is None:
                                upper = longValue
                            else:
                                raise RangeSyntaxError("range must have at most lower and upper limit but found another number: %r" % nextValue)
                        elif lower is None:
                            lower = longValue
                        else:
                            raise RangeSyntaxError(u"number must be followed by colon (:) but found: %r" % nextValue)
                    elif afterHyphen:
                        raise RangeSyntaxError(u"hyphen (-) must be followed by number but found: %r" % nextValue)
                    elif (nextType == token.OP) and (nextValue == "-"):
                        afterHyphen = True
                    elif (nextType == token.OP) and (nextValue == ":"):
                        if colonFound:
                            raise RangeSyntaxError(u"range item must contain at most one colon (:)")
                        colonFound = True
                    else:
                        message = u"range must be specified using integer numbers, text, symbols and colon (:) but found: %r [token type: %r]" % (nextValue, nextType)
                        raise RangeSyntaxError(message)
                    nextToken = tokens.next()
                if afterHyphen:
                    raise RangeSyntaxError(u"hyphen (-) at end must be followed by number")

                # Decide upon the result.
                if (lower is None):
                    if (upper is None):
                        if colonFound:
                            # Handle ":".
                            # TODO: Handle ":" same as ""?
                            raise RangeSyntaxError(u"colon (:) must be preceded and/or succeeded by number")
                        else:
                            # Handle "".
                            result = None
                    else:
                        assert colonFound
                        # Handle ":y".
                        result = (None, upper)
                elif colonFound:
                    # Handle "x:" and "x:y".
                    if (upper is not None) and (lower > upper):
                        raise RangeSyntaxError(u"lower range %d must be greater or equal to upper range %d" % (lower, upper))
                    result = (lower, upper)
                else:
                    # Handle "x".
                    result = (lower, lower)
                if result is not None:
                    for item in self._items:
                        if self._itemsOverlap(item, result):
                            # TODO: use _repr_item() or something to display item in error message.
                            raise RangeSyntaxError(u"range items must not overlap: %r and %r"
                                                   % (self._repr_item(item), self._repr_item(result)))
                    self._items.append(result)
                if _tools.isEofToken(nextToken):
                    endReached = True
Example #5
0
    def __init__(self, text, default=None):
        """
        Setup a range as specified by ``text``.

        ``text`` must be of the form "lower:upper" or "limit". In case ``text`` is empty (""), any
        value will be accepted by `validate()`. For example, "1:40" accepts values between 1
        and 40.

        ``default`` is an alternative text to use in case ``text`` is ``None`` or empty.
        """
        assert default is None or default.strip(), u"default=%r" % default

        # Find out if a `text` has been specified and if not, use optional `default` instead.
        hasText = (text is not None) and text.strip()
        if not hasText and default is not None:
            text = default
            hasText = True

        if not hasText:
            # Use empty ranges.
            self._description = None
            self._items = None
        else:
            self._description = text
            self._items = []
            # TODO: Consolidate code with `DelimitedDataFormat._validatedCharacter()`.
            tokens = tokenize.generate_tokens(StringIO.StringIO(text).readline)
            endReached = False
            while not endReached:
                lower = None
                upper = None
                colonFound = False
                afterHyphen = False
                nextToken = tokens.next()
                while not _tools.isEofToken(
                        nextToken) and not _tools.isCommaToken(nextToken):
                    nextType = nextToken[0]
                    nextValue = nextToken[1]
                    if nextType in (token.NAME, token.NUMBER, token.STRING):
                        if nextType == token.NUMBER:
                            try:
                                if nextValue[:2].lower() == "0x":
                                    nextValue = nextValue[2:]
                                    base = 16
                                else:
                                    base = 10
                                longValue = long(nextValue, base)
                            except ValueError:
                                raise RangeSyntaxError(
                                    u"number must be an integer but is: %r" %
                                    nextValue)
                            if afterHyphen:
                                longValue = -1 * longValue
                                afterHyphen = False
                        elif nextType == token.NAME:
                            try:
                                longValue = tools.SYMBOLIC_NAMES_MAP[
                                    nextValue.lower()]
                            except KeyError:
                                validSymbols = _tools.humanReadableList(
                                    sorted(tools.SYMBOLIC_NAMES_MAP.keys()))
                                raise RangeSyntaxError(
                                    u"symbolic name %r must be one of: %s" %
                                    (nextValue, validSymbols))
                        elif nextType == token.STRING:
                            if len(nextValue) != 3:
                                raise RangeSyntaxError(
                                    u"text for range must contain a single character but is: %r"
                                    % nextValue)
                            leftQuote = nextValue[0]
                            rightQuote = nextValue[2]
                            assert leftQuote in "\"\'", u"leftQuote=%r" % leftQuote
                            assert rightQuote in "\"\'", u"rightQuote=%r" % rightQuote
                            longValue = ord(nextValue[1])
                        if colonFound:
                            if upper is None:
                                upper = longValue
                            else:
                                raise RangeSyntaxError(
                                    "range must have at most lower and upper limit but found another number: %r"
                                    % nextValue)
                        elif lower is None:
                            lower = longValue
                        else:
                            raise RangeSyntaxError(
                                u"number must be followed by colon (:) but found: %r"
                                % nextValue)
                    elif afterHyphen:
                        raise RangeSyntaxError(
                            u"hyphen (-) must be followed by number but found: %r"
                            % nextValue)
                    elif (nextType == token.OP) and (nextValue == "-"):
                        afterHyphen = True
                    elif (nextType == token.OP) and (nextValue == ":"):
                        if colonFound:
                            raise RangeSyntaxError(
                                u"range item must contain at most one colon (:)"
                            )
                        colonFound = True
                    else:
                        message = u"range must be specified using integer numbers, text, symbols and colon (:) but found: %r [token type: %r]" % (
                            nextValue, nextType)
                        raise RangeSyntaxError(message)
                    nextToken = tokens.next()
                if afterHyphen:
                    raise RangeSyntaxError(
                        u"hyphen (-) at end must be followed by number")

                # Decide upon the result.
                if (lower is None):
                    if (upper is None):
                        if colonFound:
                            # Handle ":".
                            # TODO: Handle ":" same as ""?
                            raise RangeSyntaxError(
                                u"colon (:) must be preceded and/or succeeded by number"
                            )
                        else:
                            # Handle "".
                            result = None
                    else:
                        assert colonFound
                        # Handle ":y".
                        result = (None, upper)
                elif colonFound:
                    # Handle "x:" and "x:y".
                    if (upper is not None) and (lower > upper):
                        raise RangeSyntaxError(
                            u"lower range %d must be greater or equal to upper range %d"
                            % (lower, upper))
                    result = (lower, upper)
                else:
                    # Handle "x".
                    result = (lower, lower)
                if result is not None:
                    for item in self._items:
                        if self._itemsOverlap(item, result):
                            # TODO: use _repr_item() or something to display item in error message.
                            raise RangeSyntaxError(
                                u"range items must not overlap: %r and %r" %
                                (self._repr_item(item),
                                 self._repr_item(result)))
                    self._items.append(result)
                if _tools.isEofToken(nextToken):
                    endReached = True