I am trying to parse lists, like [1.0, 3.9]
, and I would like to raise a custom exception when the list is empty. I followed this https://stackoverflow.com/a/13409786/2528668 but without much success.
Here is what I have so far:
class EmptyListError(ParseFatalException):
"""Exception raised by the parser for empty lists."""
def __init__(self, s, loc, msg):
super().__init__(s, loc, 'Empty lists not allowed \'{}\''.format(msg))
def hell_raiser(s, loc, toks):
raise EmptyListError(s, loc, toks[0])
START, END = map(Suppress, '[]')
list_t = START + delimitedList(pyparsing_common.sci_real).setParseAction(lambda s, loc, toks: hell_raiser(s, loc, toks) if not toks else toks) + END
tests = """
[1.0, 1.0, 1.0]
[]
[ ]
""".splitlines()
for test in tests:
if not test.strip():
continue
try:
print(test.strip())
result = list_t.parseString(test)
except ParseBaseException as pe:
print(pe)
else:
print(result)
which prints:
[1.0, 1.0, 1.0]
[1.0, 1.0, 1.0]
[]
Expected real number with scientific notation (at char 1), (line:1, col:2)
[ ]
Expected real number with scientific notation (at char 6), (line:1, col:7)
delimitedList
will not match an empty list, so your parse action will never run. I changed your parser slightly to make the list inside []
's optional, and then run your hellRaiser
parse action:
list_t = START + Optional(delimitedList(pyparsing_common.sci_real)) + END
list_t.setParseAction(lambda s, loc, toks: hell_raiser(s, loc, toks) if not toks else toks)
Gets your desired output:
[1.0, 1.0, 1.0]
[1.0, 1.0, 1.0]
[]
Empty lists not allowed '[]' (at char 0), (line:1, col:1)
[ ]
Empty lists not allowed '[]' (at char 0), (line:1, col:1)
You could also replace your parse action with a boolean condition, in this case, simply bool
- the built-in method will evaluate against the list of tokens, and if empty will fail the condition.
list_t.addCondition(bool, message="Empty lists not allowed", fatal=True)
Gets this:
[1.0, 1.0, 1.0]
[1.0, 1.0, 1.0]
[]
Empty lists not allowed (at char 0), (line:1, col:1)
[ ]
Empty lists not allowed (at char 0), (line:1, col:1)
Lastly, check out the runTests()
method on ParserElement
. I was writing that "test-the-string-and-dump-the-results-or-catch-the-exception" loop so many times, I decided to just add a testing convenience function.