""" ``lexer`` module
"""
import os.path
import re
from warnings import warn
from wheezy.html.ext.parser import (
parse_known_function,
parse_name,
parse_params,
parse_str_or_int,
)
from wheezy.html.utils import html_id
[docs]class Preprocessor(object):
"""Generic widget preprocessor."""
CHECKBOX = None
ERROR = None
ERROR_CLASS0 = None
ERROR_CLASS1 = None
EXPRESSION = None
HIDDEN = '<input type="hidden" name="%(name)s" value="%(value)s" />'
INPUT = None
LABEL = '<label for="%(id)s"%(attrs)s%(class)s>%(value)s</label>'
MESSAGE = None
MULTIPLE_CHECKBOX = None
MULTIPLE_HIDDEN = None
PREPEND = None
RADIO = None
SELECT = None
TEXTAREA = (
'<textarea id="%(id)s" name="%(name)s"%(attrs)s%(class)s>'
"%(value)s</textarea>"
)
# region: preprocessing
def __init__(self, widgets_pattern):
self.widgets = {
"checkbox": self.checkbox,
"dropdown": self.dropdown,
"emptybox": self.emptybox,
"error": self.error,
"hidden": self.hidden,
"info": self.info,
"label": self.label,
"listbox": self.listbox,
"multiple_checkbox": self.multiple_checkbox,
"multiple_hidden": self.multiple_hidden,
"multiple_select": self.listbox,
"password": self.password,
"radio": self.radio,
"select": self.dropdown,
"textarea": self.textarea,
"textbox": self.textbox,
"warning": self.warning,
}
assert "%(widgets)s" in widgets_pattern
self.RE_WIDGETS = re.compile(
widgets_pattern % {"widgets": "|".join(self.widgets.keys())}
)
def __call__(self, text, **kwargs):
"""Preprocess input text."""
result = []
start = 0
for m in self.RE_WIDGETS.finditer(text):
result.append(text[start : m.start()])
start = m.end()
args = m.groupdict()
widget = self.widgets[args.pop("widget")]
result.append(widget(**args))
if start > 0 and self.PREPEND:
result.insert(0, self.PREPEND)
result.append(text[start:])
return "".join(result)
# region: helpers
[docs] def expression(self, text, expr_filter=""):
"""Interpretate ``text`` as string expression or
python expression.
"""
value = parse_str_or_int(text)
return value or self.EXPRESSION % {
"expr": text,
"expr_filter": expr_filter,
}
[docs] def join_attrs(self, kwargs):
"""Joins ``kwargs`` as html attributes."""
if kwargs:
return " " + " ".join(
[
'%s="%s"' % (k, self.expression(kwargs[k]))
for k in sorted(kwargs.keys())
]
)
else:
return ""
[docs] def error_class(self, name, class_):
"""Checks for error and add css class error."""
if class_:
return self.ERROR_CLASS1 % {
"name": name,
"class": self.expression(class_),
}
else:
return self.ERROR_CLASS0 % {"name": name}
# region: widgets
[docs] def hidden(self, expr, params, expr_filter):
"""HTML element input hidden."""
name = parse_name(expr)
return self.HIDDEN % {
"name": name,
"value": self.expression(expr, expr_filter),
}
[docs] def multiple_hidden(self, expr, params, expr_filter):
"""Multiple HTML element input of type hidden."""
name = parse_name(expr)
return self.MULTIPLE_HIDDEN % {
"name": name,
"value": expr,
"expr_filter": expr_filter,
}
[docs] def label(self, expr, params, expr_filter):
"""HTML element label."""
name = parse_name(expr)
args, kwargs = parse_params(params)
class_ = kwargs.pop("class", None)
return self.LABEL % {
"id": html_id(name),
"name": name,
"value": self.expression(args[0], expr_filter),
"attrs": self.join_attrs(kwargs),
"class": self.error_class(name, class_),
}
[docs] def emptybox(self, expr, params, expr_filter):
"""HTML element input of type text. Value is rendered
only if evaluated to boolean True.
"""
return self.input_helper(expr, params, expr_filter, "empty")
[docs] def textbox(self, expr, params, expr_filter):
"""HTML element input of type text. Value is rendered
only if it is not None or ''.
"""
return self.input_helper(expr, params, expr_filter, "text")
[docs] def password(self, expr, params, expr_filter):
"""HTML element input of type password. Value is rendered
only if it is not None or ''.
"""
return self.input_helper(expr, params, expr_filter, "password")
[docs] def textarea(self, expr, params, expr_filter):
"""HTML element textarea."""
name = parse_name(expr)
args, kwargs = parse_params(params)
kwargs.setdefault("rows", '"9"')
kwargs.setdefault("cols", '"40"')
class_ = kwargs.pop("class", None)
return self.TEXTAREA % {
"id": html_id(name),
"name": name,
"value": self.expression(expr, expr_filter),
"attrs": self.join_attrs(kwargs),
"class": self.error_class(name, class_),
}
[docs] def checkbox(self, expr, params, expr_filter):
"""HTML element input of type checkbox."""
name = parse_name(expr)
args, kwargs = parse_params(params)
class_ = kwargs.pop("class", None)
return self.CHECKBOX % {
"id": html_id(name),
"name": name,
"value": expr,
"attrs": self.join_attrs(kwargs),
"class": self.error_class(name, class_),
}
[docs] def multiple_checkbox(self, expr, params, expr_filter):
"""Multiple HTML element input of type checkbox."""
name = parse_name(expr)
args, kwargs = parse_params(params)
choices = kwargs.pop("choices")
class_ = kwargs.pop("class", None)
return self.MULTIPLE_CHECKBOX % {
"id": html_id(name),
"name": name,
"choices": choices,
"value": expr,
"expr_filter": expr_filter,
"attrs": self.join_attrs(kwargs),
"class": self.error_class(name, class_),
}
[docs] def radio(self, expr, params, expr_filter):
"""A group of HTML input elements of type radio."""
name = parse_name(expr)
args, kwargs = parse_params(params)
class_ = kwargs.pop("class", None)
choices = kwargs.pop("choices")
return self.RADIO % {
"id": html_id(name),
"name": name,
"choices": choices,
"value": expr,
"expr_filter": expr_filter,
"attrs": self.join_attrs(kwargs),
"class": self.error_class(name, class_),
}
[docs] def dropdown(self, expr, params, expr_filter):
"""HTML element select."""
name = parse_name(expr)
args, kwargs = parse_params(params)
class_ = kwargs.pop("class", None)
choices = kwargs.pop("choices")
return self.SELECT % {
"id": html_id(name),
"name": name,
"choices": choices,
"value": expr,
"expr_filter": expr_filter,
"attrs": self.join_attrs(kwargs),
"class": self.error_class(name, class_),
}
[docs] def listbox(self, expr, params, expr_filter):
"""HTML element select of type multiple."""
name = parse_name(expr)
args, kwargs = parse_params(params)
class_ = kwargs.pop("class", None)
choices = kwargs.pop("choices")
return self.MULTIPLE_SELECT % {
"id": html_id(name),
"name": name,
"choices": choices,
"value": expr,
"expr_filter": expr_filter,
"attrs": self.join_attrs(kwargs),
"class": self.error_class(name, class_),
}
[docs] def error(self, expr, params, expr_filter):
"""General error message or field error."""
name = parse_name(expr)
args, kwargs = parse_params(params)
class_ = kwargs.pop("class", "")
if class_:
class_ = " " + self.expression(class_)
if "." not in expr:
name = "__ERROR__"
kwargs["class"] = '"error-message' + class_ + '"'
else:
kwargs["class"] = '"error' + class_ + '"'
return self.ERROR % {
"name": name,
"attrs": self.join_attrs(kwargs),
"expr_filter": expr_filter,
}
[docs] def info(self, expr, params, expr_filter):
"""General info message."""
return self.message_helper(expr, params, expr_filter, "info")
[docs] def warning(self, expr, params, expr_filter):
"""General warning message."""
return self.message_helper(expr, params, expr_filter, "warning")
[docs] def message_helper(self, expr, params, expr_filter, msg_class):
"""General info message."""
args, kwargs = parse_params(params)
class_ = kwargs.pop("class", "")
if class_:
class_ = " " + self.expression(class_)
if "." not in expr:
class_ = "-message" + class_
kwargs["class"] = '"' + msg_class + class_ + '"'
return self.MESSAGE % {
"value": expr,
"info": self.expression(expr, expr_filter),
"attrs": self.join_attrs(kwargs),
}
[docs]class WhitespacePreprocessor(object):
"""Whitespace preprocessor."""
def __init__(self, rules, ignore_rules=None):
self.rules = rules
self.ignore_rules = ignore_rules
def __call__(self, text, **kwargs):
if self.ignore_rules:
for ignore_rule in self.ignore_rules:
start = 0
result = []
for m in ignore_rule.finditer(text):
result.append(self.cleanup(text[start : m.start()]))
result.append(m.group())
start = m.end()
else:
result.append(self.cleanup(text[start:]))
text = "".join(result)
return text
else:
return self.cleanup(text)
def cleanup(self, text):
for r, s in self.rules:
text = r.sub(s, text)
return text
[docs]class InlinePreprocessor(object):
"""Inline preprocessor"""
def __init__(self, pattern, directories, strategy=None):
self.pattern = pattern
self.directories = directories
if strategy:
self.strategy = strategy
def __call__(self, text, **kwargs):
result = []
start = 0
for m in self.pattern.finditer(text):
result.append(text[start : m.start()])
start = m.end()
path = m.group("path")
result.append(self(self.strategy(path)))
if start:
result.append(text[start:])
return "".join(result)
else:
return text
def strategy(self, path):
path = path.lstrip("/")
for d in self.directories:
abspath = os.path.abspath(os.path.join(d, path))
if os.path.exists(abspath) and os.path.isfile(abspath):
f = open(abspath, "r")
try:
return f.read()
finally:
f.close()
warn('InlinePreprocessor: "%s" not found.' % path)
return ""