Exemple #1
0
 def compiler(self, pattern, flags):
     # pylint: disable=no-self-use
     try:
         return re.compile(pattern, flags)
     except re.error as e:
         raise ParseException(str(e))
 def parseImpl(self, instring, loc, doActions=True):
     test = instring[loc:loc + self.matchLen]
     if test.upper() == self.match:
         return loc + self.matchLen, test
     #~ raise ParseException( instring, loc, self.errmsg )
     raise ParseException(instring, loc, self.errmsg, self)
Exemple #3
0
def _check_n_tokens(tokens, n_tokens, name):
    if not len(tokens) == n_tokens:
        err = "{} take {} values. You gave {}"
        err = err.format(name, n_tokens, len(tokens))
        raise ParseException(err)
def _check_keyword(tokens):
    if tokens[0][-1] == '-':
        raise ParseException("'-' found at the end of keyword.")
    return None
Exemple #5
0
def post_process(res, allow_implicit=True):
    """
    Perform post-processing on the results of the date range parsing.

    At the moment this consists mainly of ensuring that any missing information is filled in.
    For example, if no years are specified at all in the string then both years are set to the
    current year, and if one part of the string includes no month or year then these are
    filled in from the other part of the string.

    :param res: The results from the parsing operation, as returned by the parseString function
    :param allow_implicit: If implicit dates are allowed
    :return: the results with populated date information
    """

    # Get current date
    today = datetime.date.today()

    if not allow_implicit:
        if ('start' in res and 'day' not in res.start) or ('end' in res and 'day' not in res.end):
            raise ParseException("Couldn't parse resulting datetime")

    if 'start' not in res:
        # We have a single date, not a range
        res['start'] = {}

        if 'month' not in res.end and 'day' not in res.end:
            # We have only got a year, so go from start to end of the year
            res['start']['year'] = res.end.year
            res['start']['month'] = 1
            res['start']['day'] = 1

            res['end']['month'] = 12
            res['end']['day'] = 31
            return res
        elif 'month' in res.end and 'day' not in res.end:

            if not isinstance(res.end.month, int):
                raise ParseException("Couldn't parse resulting datetime")

            # special case - treat bare month as a range from start to end of month
            if 'year' not in res.end or res.end.year == "":
                res['start']['year'] = today.year
                res['end']['year'] = today.year
            else:
                res['start']['year'] = res.end.year

            res['start']['day'] = 1
            res['start']['month'] = res.end.month

            res['end']['day'] = calendar.monthrange(
                res['start']['year'], res.end.month)[1]
        else:
            res['start']['day'] = res.end.day
            res['start']['month'] = res.end.month

            if 'year' not in res.end:
                res['start']['year'] = today.year
            else:
                res['start']['year'] = res.end.year

            res['end'] = None

        return res

    if 'month' not in res.end and 'month' not in res.start and \
            'day' not in res.end and 'day' not in res.start:
        # No months or days given, just years
        res['start']['month'] = 1
        res['start']['day'] = 1

        res['end']['month'] = 12
        res['end']['day'] = 31
        return res

    # Sort out years
    if 'year' not in res.end:
        res.end['year'] = today.year
        res.start['year'] = today.year
    elif 'year' not in res.start:
        res.start['year'] = res.end.year

    # Sort out months
    if 'month' not in res.start:
        res.start['month'] = res.end.month

    if 'day' not in res.start or res.start['day'] == '':
        res.start['day'] = 1

    if res.end.month and ('day' not in res.end or res.end['day'] == ''):

        res.end['day'] = calendar.monthrange(res.end.year, res.end.month)[1]

    return res
Exemple #6
0
 def containerIdParseAction(s, loc, tokens):
     v = int(tokens[0])
     if not v in container_ids:
         raise ParseException(s, loc, "Not a valid container id")
     return v
Exemple #7
0
def format_and_raise_parse_error(exc):
    msg = ParseException.explain(exc, depth=0)
    raise ParseError(msg)
Exemple #8
0
def assertParserResultDict(parser_element,
                           test_strings,
                           expected_results,
                           assert_flag=True,
                           message=''):
    """
    A nice unit test tool which provides an assert()-like function
    that takes an string, parse the string, takes its computed
    Pythonized list/dict and compares the result against its
    expected Pythonized result.

    :param parser_element:  ParserElement class to exercise
    :param test_strings:  A string in which to be parsed by parser_element.
                          Or it can be a list of strings ['a', 'b'].
    :param expected_results:  A Python list in which to expect
                              If a_test_data is a list, then this argument
                              shall also be a list of expected result
    :param assert_flag:  If True, then expected result must match or an
                         exception gets raised.
                         If False, then parse MUST fail or expected
                         result does not match, else an exception
                         gets raised
    :return: Always returns True (exception handles the False, like
             an assert() class would do)
    """
    retsts = None

    def incr_pos(fn):
        def _inner(*args):
            global pos
            pos += 1
            print("\t" * pos, end="")
            return fn(*args)

        return _inner

    def decr_pos(fn):
        def _inner(*args):
            global pos
            print("\t" * pos, end="")
            pos -= 1
            return fn(*args)

        return _inner

    import pyparsing
    pyparsing._defaultStartDebugAction = incr_pos(pyparsing._defaultStartDebugAction)
    pyparsing._defaultSuccessDebugAction = decr_pos(pyparsing._defaultSuccessDebugAction)
    pyparsing._defaultExceptionDebugAction = decr_pos(pyparsing._defaultExceptionDebugAction)
    try:
        parser_element = parser_element.setDebug(True)
        result = parser_element.parseString(test_strings, parseAll=True)
        from pprint import PrettyPrinter
        pp = PrettyPrinter(indent=2, width=66, compact=False)
        if result.asDict() == {}:
            print('Dict() empty; BAD result:', end='')
            pp.pprint(result)
            retsts = False
        else:
            print('Good result:')
            pp.pprint(result.asDict())
            # Convert ParserElement into Python List[]
            retsts = (result.asDict() == expected_results)
        print('expecting: ')
        pp.pprint(expected_results)
    except ParseException as pe:
        print('ParseException:')
        print(pe.line)  # affected data content
        print(' ' * (pe.column - 1) + '^')  # Show where the error occurred
        print(pe)
        ParseException.explain(pe)
        retsts = False
    except ParseSyntaxException as pe:
        print('ParseSyntaxException:')
        print(test_strings)  # affected data content
        print(' ' * (pe.column - 1) + '^')  # Show where the error occurred
        print(pe)
        # print(parser_element.errmsg)
        retsts = False
        # raise InvalidConfiguration(error_msg)
    if retsts == assert_flag:
        print('assert(True)')
        return True
    else:
        errmsg = 'Error(assert=' + str(False) + '): ' + message + '\"' + test_strings + '\".'
        raise SyntaxError(errmsg)
Exemple #9
0
def test_main(tm_parse_element):
    """
    python_script              # defaults to STDIN for input a_file (good for quick test or cut-n-paste)
    python_script -t           # Exercise built-in unit test
    python_script <filespec>   # Read a_file and syntax-check it
    python_script -v           # Increase verbosity level
    python_script -d           # Increase PyParsing debugging
    :return:
    """
    pgm_basename = os.path.basename(sys.argv[0])

    prgm_desc = 'Exercise or test the {} function in {} python script against ParserElement "{}"'.format(
        tm_parse_element.__class__.__name__, pgm_basename, tm_parse_element)
    parser = argparse.ArgumentParser(description=prgm_desc)
    parser.add_argument('-v', '--verbose', action='store_true', help='Run with extra messages')
    parser.add_argument('-d', '--debug', action='store_true',
                        help='Run with PyParsing debugging enabled; outputs "Match/Matched" a_debug lines')

    if unix_pipe_support:
        default_arg1 = '-'
    else:
        default_arg1 = None
    # nagrs='?' is zero or one argument exactly
    parser.add_argument('filespec',
                        type=argparse.FileType('r'),
                        default=default_arg1,
                        nargs='?',
                        help='Input a_file to read and parse')
    args = parser.parse_args()
    if args.verbose:
        print('"Number of arguments: ', len(sys.argv))
        print('The arguments are: ', str(sys.argv))
        print('argparse.args:', args)
    retsts = 0
    test_data = None
    if not unix_pipe_support:
        # test if file exist
        if args.filespec is None:
            retsts = errno.ENOTTY  # Most people don't want UNIX pipe support
        elif not os.access(args.filespec.name, os.R_OK):
            print("Cannot read {} file. Exiting...".format(args.filespec.name))

    # If no a_file given, we default to STDIN as a a_file to be opened
    # Naturally, you'll have to press Ctrl-D to close the a_file.
    if args.verbose:
        print('parser_element:', tm_parse_element)
    try:
        test_data = args.filespec.read()
        args.filespec.close()
    except Exception as pe:
        print('Exception:')
        print(pe)
        retsts = errno.EBADFD

    if test_data:
        if args.debug:
            tm_parse_element.setDebug()
        try:
            tm_parse_element.ignore(cppStyleComment)
            tm_parse_element.ignore(pythonStyleComment)
            result = tm_parse_element.parseString(test_data, parseAll=True)
            result_text = result.asList()
            print("Result: ", result_text)
            if len(result) == 0:
                retsts = errno.EBADE
            else:
                retsts = 0
        except ParseException as pe:
            print('ParseException:')
            print(pe.line)  # affected data content
            print(' ' * (pe.column - 1) + '^')  # Show where the error occurred
            print(pe)
            ParseException.explain(pe)
            retsts = errno.ELIBSCN
        except ParseSyntaxException as pe:
            print('ParseSyntaxException:')
            print(test_data)  # affected data content
            print(' ' * (pe.column - 1) + '^')  # Show where the error occurred
            print(pe)
            retsts = errno.ELIBBAD
    else:
        retsts = errno.ENODATA
        if args.verbose:
            print("test_data is empty")

    # Build return values
    return_list = {}
    return_list['verbosity'] = args.verbose
    return_list['a_debug'] = args.debug
    return_list['filespec'] = args.filespec
    return_list['errcode'] = retsts
    return return_list
Exemple #10
0
 def validate_and_convert_number(tokens):
     try:
         return float(tokens[0])
     except ValueError:
         raise ParseException("Invalid number (%s)" % tokens[0])
def no_keywords_allowed(s, l, t):
    wd = t[0]
    if wd in pythonKeywords:
        errmsg = "cannot not use keyword '%s' " \
                                "as an identifier" % wd
        raise ParseException(s, l, errmsg)
 def rangeCheckParseAction(string, loc, tokens):
     parsedval = tokens[0]
     if not inRangeFn(parsedval):
         raise ParseException(string, loc, outOfRangeMessage % parsedval)
def assertParseElement(a_parse_element,
                       a_test_data,
                       a_expected_result,
                       a_assert_flag=True):
    """
    A nice unit test tool which provides an assert()-like function
    that takes an string, parse the string, takes its computed
    Pythonized list/dict and compares the result against its
    expected Pythonized result.

    :param a_parse_element:  ParserElement class to exercise
    :param a_test_data:  A string in which to be parsed by a_parse_element
    :param a_expected_result:  A Python list in which to expect
    :param a_assert_flag:  If True, then expected result must match or an
                           exception gets raised.
                           If False, then parse MUST fail or expected
                           result does not match, else an exception
                           gets raised
    :return: Always returns True (exception handles the False, like
             an assert() class would do)
    """
    retsts = None

    try:
        a_parse_element = a_parse_element.setDebug(True)
        result = a_parse_element.parseString(a_test_data, parseAll=True)
        pp = PrettyPrinter(indent=2, width=66, compact=False)
        if result.asDict() == {}:
            print('***BAD***-Python-Dict result:', end='')
            pp.pprint(result)
        else:
            print('Good-Python-Dict result:')
            pp.pprint(result.asDict())
        print('expecting: ')
        pp.pprint(a_expected_result)
        # Convert ParserElement into Python List[] and compare
        retsts = (result.asDict() == a_expected_result)
    except ParseException as pe:
        print('ParseException:')
        print(pe.line)  # affected data content
        print(' ' * (pe.column - 1) + '^')  # Show where the error occurred
        print(pe)
        ParseException.explain(pe)
        retsts = False
    except ParseBaseException as pe:
        print('ParseBaseException:')
        print(a_test_data)  # affected data content
        print(' ' * (pe.column - 1) + '^')  # Show where the error occurred
        print(pe)
        retsts = False
    except ParseSyntaxException as pe:
        print('ParseSyntaxException:')
        print(a_test_data)  # affected data content
        print(' ' * (pe.column - 1) + '^')  # Show where the error occurred
        print(pe)
        retsts = False
    if retsts == a_assert_flag:
        print('assert(True)')
        return True
    else:
        print('assert(***FALSE***)')
        errmsg = 'Error(assert=' + str(False) + '): \"' + a_test_data + '\".'
        raise SyntaxError(errmsg)
Exemple #14
0
 def __init__(self, t):
     if t[0] not in ['unit', 'global']:
         raise ParseException(f'Only `unit` and `global` aggregation types are supported but `{t[0]}` received.')
     self.agg_type = t[0]
Exemple #15
0
    def __repr__(self):
        # print([t for t in self.tokens.items()])
        if 'singleterm' in self.tokens:
            if self.tokens.fieldname == '_exists_':
                return '{{ "attributes.{}": {{ "$exists": true }} }}'.format(
                    self.tokens.singleterm)
            else:
                if self.tokens.field[0] == '__default_field__':
                    return '{{ "{}": {{ "{}": "{}" }} }}'.format(
                        '__default_field__', '__default_operator__',
                        self.tokens.singleterm)
                else:
                    return '{{ "{}": {{ "$regex": "{}" }} }}'.format(
                        self.tokens.field[0], self.tokens.singleterm)
        if 'phrase' in self.tokens:
            if self.tokens.field[0] == '__default_field__':
                return '{{ "{}": {{ "{}": "{}" }} }}'.format(
                    '__default_field__', '__default_operator__',
                    self.tokens.phrase)
            else:
                return '{{ "{}": {{ "$regex": "{}" }} }}'.format(
                    self.tokens.field[0], self.tokens.phrase)
        if 'wildcard' in self.tokens:
            return '{{ "{}": {{ "$regex": "\\\\b{}\\\\b" }} }}'.format(
                self.tokens.field[0], self.tokens.wildcard)
        if 'regex' in self.tokens:
            return '{{ "{}": {{ "$regex": "{}" }} }}'.format(
                self.tokens.field[0], self.tokens.regex)

        def range_term(field, operator, range):
            if field in ['duplicateCount', 'timeout']:
                range = int(range)
            else:
                range = '"{}"'.format(range)
            return '{{ "{}": {{ "{}": {} }} }}'.format(field, operator, range)

        if 'range' in self.tokens:
            if self.tokens.range[0].lowerbound == '*':
                lower_term = '{}'
            else:
                lower_term = range_term(
                    self.tokens.field[0],
                    '$gte' if 'inclusive' in self.tokens.range[0] else '$gt',
                    self.tokens.range[0].lowerbound)
            if self.tokens.range[2].upperbound == '*':
                upper_term = '{}'
            else:
                upper_term = range_term(
                    self.tokens.field[0],
                    '$lte' if 'inclusive' in self.tokens.range[2] else '$lt',
                    self.tokens.range[2].upperbound)
            return '{{ "$and": [ {}, {} ] }}'.format(lower_term, upper_term)
        if 'onesidedrange' in self.tokens:
            return range_term(self.tokens.field[0],
                              self.tokens.onesidedrange.op,
                              self.tokens.onesidedrange.bound)
        if 'subquery' in self.tokens:
            if self.tokens.field[0] != '__default_field__':
                return '{}'.format(self.tokens.subquery[0])\
                    .replace('__default_field__', self.tokens.field[0])\
                    .replace('__default_operator__', '$regex')
            else:
                return '{}'.format(self.tokens.subquery[0])

        raise ParseException('Search term did not match query syntax: %s' %
                             self.tokens)
Exemple #16
0
def parse_hand(s, parseAll=False):
    tokens = hand.parseString(s, parseAll=parseAll)
    if tokens is not None and len(tokens) > 0:
        return tokens[0]
    else:
        raise ParseException('Error parsing hand string \'' + s + '\'')
Exemple #17
0
 def secretIdNumberParseAction(s, loc, tokens):
     v = int(tokens[0])
     if not v in secret_ids:
         raise ParseException(s, loc, "Not a valid secret id")
     return v
Exemple #18
0
 def __init__(self, t):
     if t[0] not in ["unit", "global"]:
         raise ParseException(f"Only `unit` and `global` aggregation types are supported but `{t[0]}` received.")
     self.agg_type = t[0]
 def mustMatch(tokens):
     if tokens[1] != opentag:
         raise ParseException("", 0, "")
Exemple #20
0
 def get_named_var(var_name):
     try:
         get_type(var_name)
     except ParseException:
         return _() % var_name
     raise ParseException('var name clashes with type: %s' % var_name)
Exemple #21
0
def parse_file(p: ParserElement, file_name: PathLike) -> ParseResults:
    """Apply parser `p` on file `file_name`."""
    try:
        return p.parseFile(file_name)
    except ParseException as ex:
        raise ParseException(f"Error Trying to parse: {p} in file: {file_name}") from ex
Exemple #22
0
 def dont_allow_non_comparing_terms(self, s, loc, toks):
     if isinstance(toks[0], self.BoolOperand):
         raise ParseException("Failed")
     return toks
Exemple #23
0
def parse(text, allow_implicit=True):
    """
    Parses a date range string and returns the start and end as datetimes.

    **Accepted formats:**

    This parsing routine works with date ranges and single dates, and should
    work with a wide variety of human-style string formats, including:

    - 27th-29th June 2010
    - 30 May to 9th Aug
    - 3rd Jan 1980 - 2nd Jan 2013
    - Wed 23 Jan - Sat 16 February 2013
    - Tuesday 29 May -> Sat 2 June 2012
    - From 27th to 29th March 1999
    - 1--9 Jul
    - 14th July 1988
    - 23rd October 7:30pm
    - From 07:30 18th Nov to 17:00 24th Nov

    **Notes:**

    - If an error encountered while parsing the date range then a
    `pyparsing.ParseException` will be raised.
    - If no year is specified then the current year is used.
    - All day names are ignored, so there is no checking to see whether,
    for example, the 23rd Jan 2013 is actually a Wednesday.
    - All times are ignored, assuming they are placed either before or after
    each date, otherwise they will cause an error.
    - The separators that are allows as part of the date range are `to`,
    `until`, `-`, `--` and `->`, plus the unicode em and en dashes.
    - Other punctuation, such as commas, is ignored.

    :param text: The string to parse
    :param allow_implicit: If implicit dates are allowed. For example,
    string 'May' by default treated as range
           from May, 1st to May, 31th. Setting allow_implicit to False helps avoid it.
    :return: A tuple ``(start, end)`` where each element is a datetime object.
    If the string only defines a single date then the tuple is ``(date, None)``.
    All times in the datetime objects are set to 00:00 as this function only parses dates.
    """
    parser = create_parser()

    # print text
    result = parser.parseString(text)
    # print result.dump()
    # print "----------"
    res = post_process(result, allow_implicit)
    # print res.dump()

    # Create standard dd/mm/yyyy strings and then convert to Python datetime
    # objects
    if 'year' not in res.start:
        # in case only separator was given
        raise ParseException("Couldn't parse resulting datetime")

    try:
        start_str = "%(day)s/%(month)s/%(year)s" % res.start
        start_datetime = datetime.datetime.strptime(start_str, "%d/%m/%Y")
    except ValueError:
        raise ParseException("Couldn't parse resulting datetime")

    if res.end is None:
        return start_datetime, None
    elif not res.end:
        raise ParseException("Couldn't parse resulting datetime")
    else:
        try:
            if "month" not in res.end:
                res.end["month"] = res.start["month"]
            end_str = "%(day)s/%(month)s/%(year)s" % res.end
            end_datetime = datetime.datetime.strptime(end_str, "%d/%m/%Y")
        except ValueError:
            raise ParseException("Couldn't parse resulting datetime")

        if end_datetime < start_datetime:
            # end is before beginning!
            # This is probably caused by a date straddling the change of year
            # without the year being given
            # So, we assume that the start should be the previous year
            res.start['year'] = res.start['year'] - 1
            start_str = "%(day)s/%(month)s/%(year)s" % res.start
            start_datetime = datetime.datetime.strptime(start_str, "%d/%m/%Y")

        return start_datetime, end_datetime
 def check_sub_indent(str, location, tokens):
     cur_col = col(location, str)
     if cur_col > indent_stack[-1]:
         indent_stack.append(cur_col)
     else:
         raise ParseException(str, location, "not a subentry")
def _check_toplabel(tokens):
    if tokens[0][-1] == '-':
        raise ParseException("Top level ending in '-'")
    return None
 def check_unindent(str, location, tokens):
     if location >= len(str):
         return
     cur_col = col(location, str)
     if not (cur_col < indent_stack[-1] and cur_col <= indent_stack[-2]):
         raise ParseException(str, location, "not an unindent")
def convertToFloat(s, loc, toks):
    try:
        return float(toks[0])
    except:
        raise ParseException(loc, "invalid float format %s" % toks[0])
Exemple #28
0
    def __repr__(self):
        # print([t for t in self.tokens.items()])
        if 'singleterm' in self.tokens:
            if self.tokens.fieldname == '_exists_':
                return '"attributes"::jsonb ? \'{}\''.format(
                    self.tokens.singleterm)
            elif self.tokens.fieldname in ['correlate', 'service', 'tags']:
                return '\'{}\'=ANY("{}")'.format(self.tokens.singleterm,
                                                 self.tokens.field[0])
            elif self.tokens.attr:
                tokens_attr = self.tokens.attr.replace('_', 'attributes')
                return '"{}"::jsonb ->>\'{}\' ILIKE \'%%{}%%\''.format(
                    tokens_attr, self.tokens.fieldname, self.tokens.singleterm)
            else:
                return '"{}" ILIKE \'%%{}%%\''.format(self.tokens.field[0],
                                                      self.tokens.singleterm)
        if 'phrase' in self.tokens:
            if self.tokens.field[0] == '__default_field__':
                return '"{}" ~* \'\\y{}\\y\''.format('__default_field__',
                                                     self.tokens.phrase)
            elif self.tokens.field[0] in ['correlate', 'service', 'tags']:
                return '\'{}\'=ANY("{}")'.format(self.tokens.term,
                                                 self.tokens.field[0])
            else:
                return '"{}" ~* \'\\y{}\\y\''.format(self.tokens.field[0],
                                                     self.tokens.phrase)
        if 'wildcard' in self.tokens:
            return '"{}" ~* \'\\y{}\\y\''.format(self.tokens.field[0],
                                                 self.tokens.wildcard)
        if 'regex' in self.tokens:
            return '"{}" ~* \'{}\''.format(self.tokens.field[0],
                                           self.tokens.regex)
        if 'range' in self.tokens:
            if self.tokens.range[0].lowerbound == '*':
                lower_term = '1=1'
            else:
                lower_term = '"{}" {} \'{}\''.format(
                    self.tokens.field[0],
                    '>=' if 'inclusive' in self.tokens.range[0] else '>',
                    self.tokens.range[0].lowerbound)

            if self.tokens.range[2].upperbound == '*':
                upper_term = '1=1'
            else:
                upper_term = '"{}" {} \'{}\''.format(
                    self.tokens.field[0],
                    '<=' if 'inclusive' in self.tokens.range[2] else '<',
                    self.tokens.range[2].upperbound)
            return '({} AND {})'.format(lower_term, upper_term)
        if 'onesidedrange' in self.tokens:
            return '("{}" {} \'{}\')'.format(self.tokens.field[0],
                                             self.tokens.onesidedrange.op,
                                             self.tokens.onesidedrange.bound)
        if 'subquery' in self.tokens:
            if self.tokens.attr:
                tokens_attr = 'attributes' if self.tokens.attr == '_' else self.tokens.attr
                tokens_fieldname = '"{}"::jsonb ->>\'{}\''.format(
                    tokens_attr, self.tokens.fieldname)
            else:
                tokens_fieldname = '"{}"'.format(self.tokens.fieldname
                                                 or self.tokens.field[0])
            return '{}'.format(self.tokens.subquery[0]).replace(
                '"__default_field__"', tokens_fieldname)

        raise ParseException('Search term did not match query syntax: %s' %
                             self.tokens)
Exemple #29
0
def convertToExpressionTree(tokens=None):
    if not tokens:
        raise ParseException("Failed to parse expression")
    return ParseExpression(' '.join(tokens[0]))
Exemple #30
0
 def parse(self, filepath: str) -> None:
     with open(filepath, "r") as filehandle:
         try:
             self.__grammar.parseFile(filehandle)
         except (ParseException, ParseFatalException) as e:
             raise ParserError("\n" + ParseException.explain(e, 0))