Hi, I wrote a little macro for referencing values defined in the wiki and for calculations. One has to create a page named "wiki/Defines", with lines similar to the C preprocessor syntax:
define FOO 1 define BAR 2 define FOOBAR 1+2 One can use the defines anywhere in the wiki and calculate: [[Calc(FOO)]] -> 1 [[Calc(BAR*3)]] -> 6 [[Calc(max(abs(sin(3*pi/2.)), cos(pi)))]] -> 1.0 Is this interesting for somebody? Or would you never ever use a macro that makes use of eval() for security reasons? Did I reinvent the wheel? Are there better solutions? TIA for your comments, code attached -- You received this message because you are subscribed to the Google Groups "Trac Users" group. To post to this group, send email to trac-us...@googlegroups.com. To unsubscribe from this group, send email to trac-users+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/trac-users?hl=en.
# Copyright (C) 2010 W. Martin Borgert <deba...@debian.org> # # AGPL-3 import math import re from trac.wiki.macros import WikiMacroBase from trac.wiki.model import WikiPage """ Activate it in 'trac.ini' [components] CalcMacro.* = enabled format: Calc(calculation) displays the result of a calculation arguments: calculation = a string to evaluate examples: [[Calc(1+2)]] will be replaced with 3 some builtins and everything from the "math" module can be used furthermore one can use CPP-like defines: - create a page wiki/Defines - write you defines on that page: define VELOCITY 11. define VELOCITY_UNLADEN VELOCITY define VELOCITY_LADEN VELOCITY/2 - lines, that do not follow this syntax, are ignored - now use the definition in Calc: [[Calc(99*VELOCITY)]] [[Calc(defines)]] prints a table of all defines and lists all built-ins """ class CalcMacro(WikiMacroBase): # CPP-like syntax: define FOO BAR+8 _define_re = re.compile('^\s*#?\s*define\s+(\w+)\s+(.+)$', re.M) _hash = -1 _localdict = {} _page_name = 'Defines' _safe_dict = None @staticmethod def make_dict(): "create a dictionary with useful Python builtins and math funtions" CalcMacro._safe_dict = {} for k in math.__dict__.keys(): if not k.startswith("__"): CalcMacro._safe_dict[k] = math.__dict__[k] # some builtins are useful and, hopefully, safe for k in ["abs", "bool", "chr", "complex", "divmod", "float", "hash", "int", "hex", "long", "max", "min", "oct", "pow", "round", "unichr", "False", "True"]: CalcMacro._safe_dict[k] = eval(k) @staticmethod def update_dict(content): """create the local dictionary for eval both useful Python functions and Wiki definitions""" localdict = {} localdict.update(CalcMacro._safe_dict) defines = '<table><tr><th>Define</th><th>Definition</th></tr>' for m in CalcMacro._define_re.finditer(content): try: key, value = m.group(1), m.group(2).strip() defines += '<tr><td>%s</td><td>%s</td></tr>' % (key, value) value = eval(value, {"__builtins__": None}, localdict) localdict[key] = value except Exception, e: continue defines += '<tr><td>List of built-ins</td><td>%s</td></tr>' % \ ", ".join(CalcMacro._safe_dict.keys()) defines += '</table>' localdict['defines'] = defines CalcMacro._localdict = localdict def expand_macro(self, formatter, name, argument): # only create the Python builtin dict the first time if not CalcMacro._safe_dict: CalcMacro.make_dict() db = self.env.get_db_cnx() content = WikiPage(self.env, CalcMacro._page_name, db=db).text content_hash = hash(content) # if the wiki page didn't change, no need to re-create the dict if CalcMacro._hash != content_hash: CalcMacro.update_dict(content) CalcMacro._hash = content_hash return eval(argument, {"__builtins__": None}, CalcMacro._localdict)