class ExtensionExpr(ContextExprMixin, StringExpr): """tales: TALES expression This expression can be used to call a custom named adapter providing ITALESExtension interface. """ transform = Symbol(render_extension)
def transform_attribute(node): info = "\n".join(ASTCodeGenerator(node).lines) return template("lookup(object, name, info, __filename)", lookup=Symbol(lookup_attr), object=node.value, name=ast.Str(s=node.attr), info=ast.Str(s=info), mode="eval")
def compiler(target, engine): value = template( "EXECUTE(NAME,econtext,rcontext)", EXECUTE=Symbol(execute), NAME=ast.Str(s=command), mode="eval", ) return [ast.Assign(targets=[target], value=value)]
def _leave_assignment(self, names): for name in names: for stmt in template( "deleteitem(econtext, KEY, BACKUP, __marker)", deleteitem=Symbol(deleteitem), BACKUP=identifier("backup_%s" % name, id(names)), KEY=ast.Str(s=native_string(name)), ): yield stmt
class TileExpression(StringExpr): render_tile = Static( template("cls()", cls=Symbol(TileProviderTraverser), mode='eval')) def __call__(self, target, engine): assignment = super(TileExpression, self).__call__(target, engine) return assignment + template( 'target = render_tile(context, request, target.strip())', target=target, render_tile=self.render_tile)
def emit_convert_and_escape(target, quote=None, quote_entity=None, str=unicode_string, long=long, type=type, encoded=byte_string, default_marker=None, default=None, convert=Symbol(convert_str)): # pragma: no cover if target is not None: if target is default_marker: target = default else: target = convert(target)
def __call__(self, node): name = node.id # Don't rewrite names that begin with an underscore; they are # internal and can be assumed to be locally defined. This # policy really should be part of the template program, not # defined here in the compiler. if isinstance(node.ctx, ast.Load): if self.validate_model and name.startswith("__model_"): name = node.id[8:] if not name in self.defined_models: err = ParseError( "Cannot find model", Token(name, pos=node.lineno, source=self.source, filename=self.filename)) raise err node.id = self.defined_models[name] return node if name.startswith('__') or name in self.internals: return node if name == "el": return Builtin("None") if isinstance(node.ctx, ast.Store): return store_econtext(name) aliased = self.aliases.get(name) if aliased is not None: return load(aliased) # If the name is a Python global, first try acquiring it from # the dynamic context, then fall back to the global. if name in self.builtins: return template( "getitem(econtext, key, name)", getitem=Symbol(getitem), mode="eval", key=ast.Str(s=name), name=load(name), ) # Otherwise, simply acquire it from the dynamic context. return load_econtext(name)
def visit_BindRepeat(self, node): body = [] body.append(Comment("start model-repeat-binding")) new_stack = identifier("stack", id(node)) old_stack = self._current_stack body += template("CAPTURED_STACK = STACK.capture_for_repeat()", CAPTURED_STACK=new_stack, STACK=old_stack) new_stack = identifier("stack", id(node)) self._current_stack = new_stack self._aliases.append(self._aliases[-1].copy()) model_name = identifier("model_%s" % node.alias, id(node)) self._defined_models[node.alias] = model_name inner_on_add = [] inner_on_add += self.visit(node.node) inner_on_add += template("return STACK.repeat_el", STACK=self._current_stack) on_add_name = identifier("on_add", id(node)) on_add_func = [ ast.FunctionDef(name=on_add_name, args=ast.arguments( args=[load(model_name)], defaults=(), ), body=inner_on_add) ] body += on_add_func collection = "__collection" initializer = self._engine(node.expression, store(collection)) initializer += template("BIND_REPEAT(COLLECTION, ON_ADD)", BIND_REPEAT=Symbol(bind_repeat), COLLECTION=load(collection), ON_ADD=on_add_name) body += initializer self._aliases.pop() self._current_stack = old_stack body.append(Comment("end model-repeat-binding")) return body
def visit_BindChange(self, node): body = [] body.append(Comment("start model-binding")) new_stack = identifier("stack", id(node)) old_stack = self._current_stack body += template("CAPTURED_STACK = STACK.capture()", CAPTURED_STACK=new_stack, STACK=old_stack) self._current_stack = new_stack self._aliases.append(self._aliases[-1].copy()) inner = self.visit(node.node) self._aliases.pop() self._current_stack = old_stack on_change_name = identifier("on_change", id(node)) on_change_func = [ ast.FunctionDef(name=on_change_name, args=ast.arguments( args=[], defaults=(), ), body=inner) ] if node.model_name not in self._defined_models: raise TranslationError( "Cannot find bind model on current context.", node.model_name) body += on_change_func bind_attrs = ast.Tuple( elts=[ast.Str(s=attr) for attr in node.bind_attrs], ctx=ast.Load()) bind_ons = ast.Tuple(elts=[ast.Str(s=attr) for attr in node.bind_ons], ctx=ast.Load()) body += template("BIND_CHANGE(MODEL, BIND_ONS, BIND_ATTRS, ON_CHANGE)", BIND_CHANGE=Symbol(bind_change), MODEL=load(self._defined_models[node.model_name]), BIND_ATTRS=bind_attrs, BIND_ONS=bind_ons, ON_CHANGE=on_change_name) body.append(Comment("end model-binding")) return body
def visit_BindReplay(self, node): body = [] body.append(Comment("start replay-binding")) new_stack = identifier("stack", id(node)) old_stack = self._current_stack body += template("CAPTURED_STACK = STACK.capture()", CAPTURED_STACK=new_stack, STACK=old_stack) self._current_stack = new_stack self._aliases.append(self._aliases[-1].copy()) inner = self.visit(node.node) self._aliases.pop() self._current_stack = old_stack on_event_name = identifier("on_event", id(node)) on_event_func = [ ast.FunctionDef(name=on_event_name, args=ast.arguments( args=[], defaults=(), ), body=inner) ] body += on_event_func bindable = "__bindable" body += self._engine(node.expression, store(bindable)) events = ast.Tuple(elts=[ast.Str(s=attr) for attr in node.events], ctx=ast.Load()) body += template("BIND_REPLAY(BINDABLE, EVENTS, ON_EVENT)", BIND_REPLAY=Symbol(bind_replay), BINDABLE=bindable, EVENTS=events, ON_EVENT=on_event_name) body.append(Comment("end model-binding")) return body
def set_error(token, exception): try: line, column = token.location filename = token.filename except AttributeError: line, column = 0, 0 filename = "<string>" string = safe_native(token) return template( "rcontext.setdefault('__error__', [])." "append((string, line, col, src, exc))", string=ast.Str(s=string), line=ast.Num(n=line), col=ast.Num(n=column), src=ast.Str(s=filename), sys=Symbol(sys), exc=exception, )
class ProviderExpr(expressions.ProviderExpr): transform = Symbol(render_content_provider)
class ProviderExpr(ContextExprMixin, StringExpr): """provider: TALES expression""" transform = Symbol(render_content_provider)
class TrustedPathExpr(PathExpr): traverser = Static( template("cls()", cls=Symbol(TrustedBoboAwareZopeTraverse), mode="eval"))
def visit_Name(self, node): value = self.secured.get(node.id) if value is not None: return Symbol(value) return node
def static(obj): return Static(template("obj", obj=Symbol(obj), mode="eval"))
class PathExpr(expressions.PathExpr): exceptions = zope2_exceptions traverser = Static( template("cls()", cls=Symbol(BoboAwareZopeTraverse), mode="eval"))
class ExpressionTransform(object): """Internal wrapper to transform expression nodes into assignment statements. The node input may use the provided expression engine, but other expression node types are supported such as ``Builtin`` which simply resolves a built-in name. Used internally be the compiler. """ loads_symbol = Symbol(pickle.loads) def __init__(self, engine_factory, cache, visitor, strict=True): self.engine_factory = engine_factory self.cache = cache self.strict = strict self.visitor = visitor def __call__(self, expression, target): if isinstance(target, string_type): target = store(target) try: stmts = self.translate(expression, target) except ExpressionError: if self.strict: raise exc = sys.exc_info()[1] p = pickle.dumps(exc) stmts = template("__exc = loads(p)", loads=self.loads_symbol, p=ast.Str(s=p)) token = Token(exc.token, exc.offset, filename=exc.filename) stmts += set_error(token, load("__exc")) stmts += [ast.Raise(exc=load("__exc"))] # Apply visitor to each statement for stmt in stmts: self.visitor(stmt) return stmts def translate(self, expression, target): if isinstance(target, string_type): target = store(target) cached = self.cache.get(expression) if cached is not None: stmts = [ast.Assign(targets=[target], value=cached)] elif isinstance(expression, ast.expr): stmts = [ast.Assign(targets=[target], value=expression)] else: # The engine interface supports simple strings, which # default to expression nodes if isinstance(expression, string_type): expression = Value(expression, True) kind = type(expression).__name__ visitor = getattr(self, "visit_%s" % kind) stmts = visitor(expression, target) # Add comment target_id = getattr(target, "id", target) comment = Comment(" %r -> %s" % (expression, target_id)) stmts.insert(0, comment) return stmts def visit_Value(self, node, target): engine = self.engine_factory() compiler = engine.parse(node.value) return compiler.assign_value(target) def visit_Default(self, node, target): value = annotated(node.marker) return [ast.Assign(targets=[target], value=value)] def visit_Substitution(self, node, target): engine = self.engine_factory( char_escape=node.char_escape, default=node.default, ) compiler = engine.parse(node.value) return compiler.assign_text(target) def visit_Negate(self, node, target): return self.translate(node.value, target) + \ template("TARGET = not TARGET", TARGET=target) def visit_Identity(self, node, target): expression = self.translate(node.expression, "__expression") value = self.translate(node.value, "__value") return expression + value + \ template("TARGET = __expression is __value", TARGET=target) def visit_Equality(self, node, target): expression = self.translate(node.expression, "__expression") value = self.translate(node.value, "__value") return expression + value + \ template("TARGET = __expression == __value", TARGET=target) def visit_Boolean(self, node, target): engine = self.engine_factory() compiler = engine.parse(node.value) return compiler.assign_bool(target, node.s) def visit_Interpolation(self, node, target): expr = node.value if isinstance(expr, Substitution): engine = self.engine_factory( char_escape=expr.char_escape, default=expr.default, ) elif isinstance(expr, Value): engine = self.engine_factory() else: raise RuntimeError("Bad value: %r." % node.value) interpolator = Interpolator(expr.value, node.braces_required, node.translation) compiler = engine.get_compiler(interpolator, expr.value) return compiler(target, engine) def visit_Translate(self, node, target): if node.msgid is not None: msgid = ast.Str(s=node.msgid) else: msgid = target return self.translate(node.node, target) + \ emit_translate(target, msgid, default=target) def visit_Static(self, node, target): value = annotated(node) return [ast.Assign(targets=[target], value=value)] def visit_Builtin(self, node, target): value = annotated(node) return [ast.Assign(targets=[target], value=value)]
The compilation result is cached in ``_zt_expr_registry``. """ if engine is None: engine = econtext["__zt_engine__"] key = id(engine), type, expression # cache lookup does not need to be protected by locking # (but we could potentially prevent unnecessary computations) expr = _zt_expr_registry.get(key) if expr is None: expr = engine.types[type](type, expression, engine) _zt_expr_registry[key] = expr return expr _compile_zt_expr_node = Static(Symbol(_compile_zt_expr)) class _C2ZContextWrapper(Context): """Behaves like "zope" context with vars from "chameleon" context.""" def __init__(self, c_context): self.__c_context = c_context self.__z_context = c_context["__zt_context__"] # delegate to ``__c_context`` @property def vars(self): return self def __getitem__(self, key): try:
class ProviderExpr(ContextExpressionMixin, StringExpr): transform = Symbol(render_content_provider)
class I18nExpr(ContextExprMixin, StringExpr): """i18n:context.attribute TALES expression""" transform = Symbol(render_i18n_expression)
The compilation result is cached in ``_zt_expr_registry``. """ if engine is None: engine = econtext["__zt_engine__"] key = id(engine), type, expression # cache lookup does not need to be protected by locking # (but we could potentially prevent unnecessary computations) expr = _zt_expr_registry.get(key) if expr is None: expr = engine.types[type](type, expression, engine) _zt_expr_registry[key] = expr return expr _compile_zt_expr_node = Static(Symbol(_compile_zt_expr)) # map context class to context wrapper class _context_class_registry = {} def _with_vars_from_chameleon(context): """prepare *context* to get its ``vars`` from ``chameleon``.""" cc = context.__class__ wc = _context_class_registry.get(cc) if wc is None: class ContextWrapper(_C2ZContextWrapperBase, cc): pass wc = _context_class_registry[cc] = ContextWrapper
class PathExpr(TalesExpr): path_regex = re.compile( r'^(?:(nocall|not):\s*)*((?:[A-Za-z0-9_][A-Za-z0-9_:]*)' + r'(?:/[?A-Za-z0-9_@\-+][?A-Za-z0-9_@\-\.+/:]*)*)$') interpolation_regex = re.compile(r'\?[A-Za-z][A-Za-z0-9_]+') traverser = Symbol(path_traverse) def translate(self, string, target): """ >>> from chameleon.tales import test >>> test(PathExpr('None')) is None True """ string = string.strip() if not string: return template("target = None", target=target) m = self.path_regex.match(string) if m is None: raise ExpressionError("Not a valid path-expression.", string) nocall, path = m.groups() # note that unicode paths are not allowed parts = str(path).split('/') components = [] for part in parts[1:]: interpolation_args = [] def replace(match): start, end = match.span() interpolation_args.append(part[start + 1:end]) return "%s" while True: part, count = self.interpolation_regex.subn(replace, part) if count == 0: break if len(interpolation_args): component = template("format % args", format=ast.Str(part), args=ast.Tuple( list(map(load, interpolation_args)), ast.Load()), mode="eval") else: component = ast.Str(part) components.append(component) base = parts[0] if not components: if len(parts) == 1 and (nocall or base == 'None'): return template("target = base", base=base, target=target) else: components = () call = template( "traverse(base, econtext, call, path_items)", traverse=self.traverser, base=load(base), call=load(str(not nocall)), path_items=ast.Tuple(elts=components), mode="eval", ) return template("target = value", target=target, value=call)
def __call__(self, target, engine): assignment = super(PermissionExpr, self).__call__(target, engine) return assignment + template( 'target = check_permission(context, target)', target=target, check_permission=Symbol(checkPermission))