Source code for sfepy.base.parse_conf

"""
Create pyparsing grammar for problem configuration and options.
"""
from pyparsing import (Word, Group, Suppress, Combine, Optional,
                       Forward, Empty, quotedString, oneOf, removeQuotes,
                       delimitedList, nums, alphas, alphanums,
                       Keyword, CaselessLiteral)

(lparen, rparen, lbrack, rbrack,
 lbrace, rbrace, colon, equal_sign) = map(Suppress, '()[]{}:=')

word_free_wb = Word(alphas + '@_-/.+**' + alphanums)
word_free = Forward()
word_free = word_free_wb + Optional(lbrace + word_free + rbrace + word_free)
word_free.setParseAction(lambda toks: ''.join(toks[0]))

word_strict = Word(alphas, alphas + alphanums + '_' )

integer = Combine(Optional(oneOf('+ -')) + Word(nums)).setName('integer')
cvt_int = lambda toks: int(toks[0])
integer.setParseAction(cvt_int)

boolean_true = Keyword('True', caseless=True)
boolean_true.setParseAction(lambda x: True)
boolean_false = Keyword('False', caseless=True)
boolean_false.setParseAction(lambda x: False)

boolean = boolean_true | boolean_false

none = Keyword('None', caseless=True)

cvt_none = lambda toks: [None]
none.setParseAction(cvt_none)

e = CaselessLiteral("e")
real = (Combine(Optional(oneOf('+ -')) + Word(nums) +
               '.' + Optional(Word(nums)) +
               Optional(e + Optional(oneOf('+ -')) + Word(nums))
       )| Combine(Optional(
            oneOf('+ -')) + Word(nums) +
            Optional('.') + Optional(Word(nums)) +
            e + Optional(oneOf('+ -')) + Word(nums))
       ).setName('real')
cvt_real = lambda toks: float(toks[0])
real.setParseAction(cvt_real)

cmplx = real + CaselessLiteral('j')
cvt_cmplx = lambda toks: complex(toks[0])
cmplx.setParseAction(cvt_cmplx)

array_index = integer + Optional(colon + integer +
                                 Optional(colon + integer))
cvt_array_index = lambda toks: int(toks[0]) if len(toks) == 1 \
                  else slice(*toks)
array_index.setParseAction(cvt_array_index)
array_braces = lbrack + array_index + rbrack

[docs]def create_bnf(allow_tuple=False, free_word=False): word = word_free if free_word else word_strict defs = get_standard_type_defs(word) empty = Empty() empty.setParseAction( lambda toks: [{}]) if allow_tuple: return defs['dict'].inner | defs['tuple'].inner | empty else: return defs['dict'].inner | empty
[docs]def list_of(element, *elements): """ Return lexical element that parses a list of items. The items can be a one or several lexical elements. For example, result of ``list_of(real, integer)`` parses list of real or integer numbers. """ for e in elements: element ^= e lst = delimitedList(element) return lst + Optional(Suppress(','))
[docs]def get_standard_type_defs(word=word_free): """ Return dict of the pyparsing base lexical elements. The compound types (tuple, list, dict) can contain compound types or simple types such as integers, floats and words. Parameters ---------- word : lexical element A custom lexical element for word. Returns ------- defs : dict The dictionary with the following items: - tuple: (..., ..., ...) - list: [..., ...., ...] - dict: {...:..., ...:..., ....} or {...=..., ...=..., ....} - list_item: any of preceding compound types or simple types """ tuple_str = Forward() list_str = Forward() dict_str = Forward() cvt_tuple = lambda toks : [ tuple(toks.asList()) ] cvt_dict = lambda toks: [ dict(toks.asList())] list_item = (none ^ boolean ^ cmplx ^ real ^ integer ^ list_str ^ tuple_str ^ dict_str ^ quotedString.setParseAction(removeQuotes) ^ word) list_item2 = list_item | Empty().setParseAction(lambda: [None]) tuple_str.inner = Empty() ^ list_of(list_item) list_str.inner = tuple_str.inner.copy() tuple_str.inner.setParseAction(cvt_tuple) tuple_str << (lparen + tuple_str.inner + rparen) list_str.inner.setParseAction(lambda toks: [toks.asList()]) list_str << (lbrack + list_str.inner + rbrack) dict_entry = Group(list_item + (colon | equal_sign) + list_item2) dict_str.inner = Empty() ^ list_of(dict_entry) dict_str.inner.setParseAction(cvt_dict) dict_str << (lbrace + (dict_str.inner | Empty().setParseAction( lambda x: [{}] ) ) + rbrace) defs = {'tuple' : tuple_str, 'list' : list_str, 'dict' : dict_str, 'list_item' : list_item} return defs
[docs]def list_dict(word=word_free): """ Return the pyparsing lexical element, that parses a string either as a list or as a dictionary. Parameters ---------- word : lexical element A custom lexical element for word. Returns ------- ld : lexical element The returned lexical element parses a string in the form ``..., ..., ...`` or ``key1:..., key2=..., key3: ...`` where ``...`` is a ``list_item`` from :func:`get_standard_type_defs()` and interprets it as a list or a dictionary. """ defs = get_standard_type_defs(word) i = defs['list_item'] arg = i.copy() arg.setParseAction(lambda t: (t[0],)) narg = word_strict + (colon | equal_sign) + i narg.setParseAction(lambda t: (t[0], t[1])) ld = Group(list_of(narg ^ arg) | Empty() ) ld.setParseAction(lambda t: ([x[0] for x in t[0] if len(x) == 1], dict([x for x in t[0] if len(x) > 1])) ) return ld