##// END OF EJS Templates
templater: abort if infinite recursion detected while compiling...
templater: abort if infinite recursion detected while compiling In this case, a template is parsed recursively with no thunk for lazy evaluation. This patch prevents recursion by putting a dummy of the same name into a cache that will be referenced while parsing if there's a recursion. changeset = {files % changeset}\n ~~~~~~~~~ = [(_runrecursivesymbol, 'changeset')]

File last commit:

r27585:60bf90eb default
r27940:cfe7da66 stable
Show More
registrar.py
128 lines | 3.7 KiB | text/x-python | PythonLexer
# registrar.py - utilities to register function for specific purpose
#
# Copyright FUJIWARA Katsunori <foozy@lares.dti.ne.jp> and others
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import
from . import (
util,
)
class funcregistrar(object):
"""Base of decorator to register a fuction for specific purpose
The least derived class can be defined by overriding 'table' and
'formatdoc', for example::
symbols = {}
class keyword(funcregistrar):
table = symbols
formatdoc = ":%s: %s"
@keyword('bar')
def barfunc(*args, **kwargs):
'''Explanation of bar keyword ....
'''
pass
In this case:
- 'barfunc' is registered as 'bar' in 'symbols'
- online help uses ":bar: Explanation of bar keyword"
"""
def __init__(self, decl):
"""'decl' is a name or more descriptive string of a function
Specification of 'decl' depends on registration purpose.
"""
self.decl = decl
table = None
def __call__(self, func):
"""Execute actual registration for specified function
"""
name = self.getname()
if func.__doc__ and not util.safehasattr(func, '_origdoc'):
doc = func.__doc__.strip()
func._origdoc = doc
if callable(self.formatdoc):
func.__doc__ = self.formatdoc(doc)
else:
# convenient shortcut for simple format
func.__doc__ = self.formatdoc % (self.decl, doc)
self.table[name] = func
self.extraaction(name, func)
return func
def getname(self):
"""Return the name of the registered function from self.decl
Derived class should override this, if it allows more
descriptive 'decl' string than just a name.
"""
return self.decl
def parsefuncdecl(self):
"""Parse function declaration and return the name of function in it
"""
i = self.decl.find('(')
if i > 0:
return self.decl[:i]
else:
return self.decl
def formatdoc(self, doc):
"""Return formatted document of the registered function for help
'doc' is '__doc__.strip()' of the registered function.
If this is overridden by non-callable object in derived class,
such value is treated as "format string" and used to format
document by 'self.formatdoc % (self.decl, doc)' for convenience.
"""
raise NotImplementedError()
def extraaction(self, name, func):
"""Execute exra action for registered function, if needed
"""
pass
class delayregistrar(object):
"""Decorator to delay actual registration until uisetup or so
For example, the decorator class to delay registration by
'keyword' funcregistrar can be defined as below::
class extkeyword(delayregistrar):
registrar = keyword
"""
def __init__(self):
self._list = []
registrar = None
def __call__(self, *args, **kwargs):
"""Return the decorator to delay actual registration until setup
"""
assert self.registrar is not None
def decorator(func):
# invocation of self.registrar() here can detect argument
# mismatching immediately
self._list.append((func, self.registrar(*args, **kwargs)))
return func
return decorator
def setup(self):
"""Execute actual registration
"""
while self._list:
func, decorator = self._list.pop(0)
decorator(func)