#encoding=utf-8
#code by ZPCCZQ
#2015-08-25

import re

def safe_eval(eval_str,**kw):
    '''
    安全eval，确保eval的内容是合法的，并且隔离的。
    **kw为可定义命名空间。
    '''
    #callback functions
    def start_structure(scanner, token): return "start structure", token
    def key(scanner, token):   return "key", token
    def value(scanner, token): 
        #非法写法
        if token.lower() == 'true'and token != 'True':
            raise 'value Error "%s"'%token
    def str_value(scanner,token):   
        return "string value",token
    def end_structure(scanner, token):  return "end start structure",token
        
    scanner = re.Scanner([
        (r"[{\[(]", start_structure),
        (r"[\w]+\s*:", key),
        (r"['\"][^'\"]+['\"]",str_value),
        (r"[\w]+", value),
        (r"\s*,\s*",None),
        (r"[})\]]", end_structure),
    ])
 
    tokens, remainder = scanner.scan(eval_str)
    #make a list of safe functions
    safe_list = ['math','acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'cosh', 'de grees', 'e', 'exp', 'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log', 'log10', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh']
    #use the list to filter the local namespace s
    safe_dict = dict([ (k, locals().get(k, None)) for k in safe_list ])
    #add any needed builtins back in.
    #由于所有内置的对象被屏蔽 __builtins__中的所有对象不可使用，所以True、False需要单独定义
    #加入命名空间
    safe_dict['True'] = True
    safe_dict['False'] = False
    safe_dict['sum'] = sum
    safe_dict['map'] = map
    safe_dict['filter'] = filter
    safe_dict['reduce'] = reduce
    safe_dict['abs'] = abs
    safe_dict['divmod'] = divmod
    safe_dict['round'] = round
    for k in kw:
        if k not in safe_dict:
            safe_dict[k]=kw[k]
    return eval(eval_str,{'__builtins__':None},safe_dict)

if __name__ == '__main__':
    pass

