I'm trying to write a parser to handle response data from a registrar's API. The format isn't one that I've seen before, so this might be really easy; If anyone recognizes it, let me know and there is probably a pre-existing library to deal with it. But for now I'm operating on the assumption that I'll need to parse it myself.
My grammar looks like this:
equals = Literal("=").suppress()
lbracket = Literal("[").suppress()
rbracket = Literal("]").suppress()
lbrace = Literal("{").suppress()
rbrace = Literal("}").suppress()
value_dict = Forward()
value_list = Forward()
value_string = Word(alphanums + "@. ")
value = value_list ^ value_dict ^ value_string
values = Group(delimitedList(value, ","))
value_list << lbracket + values + rbracket
identifier = Word(alphanums + "_.")
assignment = Group(identifier + equals + Optional(value))
assignments = Dict(delimitedList(assignment, ';'))
value_dict << lbrace + assignments + rbrace
response = assignments
When I run this simple test case:
rsp = 'username=goat; errors={username=[already taken, too short]}; empty_field='
result = response.parseString(rsp)
print result.asDict()
I get the following:
{'username': 'goat', 'empty_field': '', 'errors': {'username': {}}}
errors['username'] should be a list of strings, but is showing as an empty dict. When I .dump() the params, it looks like everything is fine:
ss = response.searchString(rsp)
for i in ss:
print i.dump()
yields:
- empty_field:
- errors: [['username', ['already taken', 'too short']]]
- username: ['already taken', 'too short']
- username: goat
What am I doing wrong here?
It is a naive implementation of asDict() in the current version of pyparsing. In yoru grammar, you create ParseResults of two different styles: results with names, and results that are just plain lists. asList() simply iterates through a nested ParseResults getting lists and sublists, so asDict() works similarly. However, asDict() really needs to be a little smarter about the types of values that there can be - for now, this is a bug in pyparsing.
EDIT
To work around this, you need to do a little work to store the lists as actual lists, not as ParseResults. Redefine the values expression to:
values = delimitedList(value, ",").setParseAction(lambda toks: [toks.asList()])
Since this will return the parsed list not as a ParseResults, but as an actual list, toDict() will not try to turn it into a dict.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With