""" ``parser`` module
"""
import re
known_functions = ["format"]
RE_ARGS = re.compile(r'\s*(?P<expr>(([\'"]).*?\3|.+?))\s*\,')
RE_KWARGS = re.compile(
r'\s*(?P<name>\w+)\s*=\s*(?P<expr>([\'"].*?[\'"]|.+?))\s*\,'
)
RE_STR_VALUE = re.compile(r'^[\'"](?P<value>.+)[\'"]$')
RE_INT_VALUE = re.compile(r"^(?P<value>(\d+))$")
RE_FUNCTIONS = re.compile(r"\.(%s)\(" % "|".join(known_functions))
RE_FUNCTION = re.compile(
r"(?P<context>.+?)\.(?P<name>%s)\((?P<args>(|.+))\)"
% "|".join(known_functions)
)
[docs]def parse_name(expr):
"""Parses name from expression of the following form::
[object.]name[.format(...]
>>> parse_name('display_name')
'display_name'
>>> parse_name('account.display_name')
'display_name'
>>> parse_name('account.display_name.format(')
'display_name'
"""
expr = RE_FUNCTIONS.split(expr)[0]
name = expr.rsplit(".", 1)[-1]
return name
[docs]def parse_known_function(expr):
""" Parses known functions.
>>> parse_known_function("dob")
('dob', 'dob')
>>> parse_known_function("dob.format()")
('dob', 'format_value(dob, None)')
>>> parse_known_function("user.dob.format(_('YYYY/MM/DD'))")
('user.dob', "format_value(user.dob, _('YYYY/MM/DD'))")
>>> parse_known_function("user.dob.format(\
format_provider=lambda value, ignore: value.strftime('%m-%d-%y'))")
('user.dob', "format_value(user.dob, format_provider=lambda value, \
ignore: value.strftime('%m-%d-%y'))")
"""
m = RE_FUNCTION.search(expr)
if not m:
return expr, expr
context = m.group("context")
name = m.group("name")
args = m.group("args") or "None"
return context, "%s_value(%s, %s)" % (name, context, args)
[docs]def parse_kwargs(text):
"""Parses key-value type of parameters.
>>> parse_kwargs('choices=account_types')
{'choices': 'account_types'}
>>> sorted(parse_kwargs('autocomplete="off", maxlength=12').items())
[('autocomplete', '"off"'), ('maxlength', '12')]
"""
kwargs = {}
for m in RE_KWARGS.finditer(text + ","):
groups = m.groupdict()
kwargs[groups["name"].rstrip("_")] = groups["expr"]
return kwargs
[docs]def parse_args(text):
"""Parses argument type of parameters.
>>> parse_args('')
[]
>>> parse_args('10, "x"')
['10', '"x"']
>>> parse_args("'x', 100")
["'x'", '100']
>>> parse_args('"Account Type:"')
['"Account Type:"']
"""
args = []
for m in RE_ARGS.finditer(text + ","):
args.append(m.group("expr"))
return args
[docs]def parse_params(text):
"""Parses function parameters.
>>> parse_params('')
([], {})
>>> parse_params('choices=account_types')
([], {'choices': 'account_types'})
>>> parse_params('"Account Type:"')
(['"Account Type:"'], {})
>>> parse_params('"Account Type:", class_="inline"')
(['"Account Type:"'], {'class': '"inline"'})
"""
if "=" in text:
args = text.split("=")[0]
if "," in args:
args = args.rsplit(",", 1)[0]
kwargs = text[len(args) :]
return parse_args(args), parse_kwargs(kwargs)
else:
return [], parse_kwargs(text)
else:
return parse_args(text), {}
[docs]def parse_str_or_int(text):
"""Interpretate ``text`` as string or int expression.
>>> parse_str_or_int('"Hello"')
'Hello'
>>> parse_str_or_int("'Hello'")
'Hello'
>>> parse_str_or_int('100')
'100'
>>> parse_str_or_int('model.username')
"""
m = RE_STR_VALUE.match(text)
if m:
return m.group("value")
else:
m = RE_INT_VALUE.match(text)
if m:
return m.group("value")
else:
return None