def keygen(*ignored, **kwds): """decorator for generating a cache key for a given function ignored: names and/or indicies of the function's arguments to 'ignore' tol: integer tolerance for rounding (default is None) deep: boolean for rounding depth (default is False, i.e. 'shallow') The decorator accepts integers (for the index of positional args to ignore, or strings (the names of the kwds to ignore). A cache key is returned, built with the registered keymap. Ignored arguments are stored in the keymap with a value of klepto.NULL. Note that for class methods, it may be useful to ignore 'self'. The decorated function will gain new methods for working with cache keys - call: __call__ the function with the most recently provided arguments - valid: True if the most recently provided arguments are valid - key: get the cache key for the most recently provided arguments - keymap: get the registered keymap [default: klepto.keymaps.keymap] - register: register a new keymap The function is not evaluated until the 'call' method is called. Both generating the key and checking for validity avoid calling the function by inspecting the function's input signature. The default keymap is keymaps.keymap(flat=True). Alternate keymaps can be set with the 'register' method on the decorated function.""" # returns (*varargs, **kwds) where all info in kwds except varargs # however, special cases (builtins, etc) return (*args, **kwds) _map = kwds.get('keymap', None) if _map is None: _map = kleptokeymap() tol = kwds.get('tol', None) deep = kwds.get('deep', False) if deep: rounded = deep_round else: rounded = simple_round # enable rounding @rounded(tol) def rounded_args(*args, **kwds): return (args, kwds) def dec(f): _args = [(), {}] _keymap = [_map] #[kleptokeymap()] def last_args(): "get the most recently provided (*args, **kwds)" return _args[0], _args[1] def func(*args, **kwds): _args[0] = args _args[1] = kwds _map = _keymap[0] args, kwds = rounded_args(*args, **kwds) args, kwds = _keygen(f, ignored, *args, **kwds) return _map(*args, **kwds) def call(): "call func with the most recently provided (*args, **kwds)" ar, kw = last_args() return f(*ar, **kw) def valid(): "check if func(*args, **kwds) is valid (without calling the function)" ar, kw = last_args() return isvalid(f, *ar, **kw) #XXX: better validate? (raises errors) def key(): "get cache 'key' for most recently provided (*args, **kwds)" ar, kw = last_args() _map = _keymap[0] ar, kw = rounded_args(*ar, **kw) ar, kw = _keygen(f, ignored, *ar, **kw) #XXX: better lookup saved key? return _map(*ar, **kw) def register(mapper): "register a new keymap instance" if isinstance(mapper, type): mapper = mapper() if not isinstance(mapper, kleptokeymap): raise TypeError("'%s' is not a klepto keymap instance" % getattr(mapper, '__name__', mapper)) _keymap[0] = mapper return def keymap(): "get the registered keymap instance" return _keymap[0] func.__ignored__ = ignored func.__func__ = f func.__args__ = last_args func.call = call func.valid = valid func.key = key func.keymap = keymap func.register = register return func return dec
def keygen(*ignored, **kwds): """decorator for generating a cache key for a given function ignored: names and/or indicies of the function's arguments to 'ignore' tol: integer tolerance for rounding (default is None) deep: boolean for rounding depth (default is False, i.e. 'shallow') The decorator accepts integers (for the index of positional args to ignore, or strings (the names of the kwds to ignore). A cache key is returned, built with the registered keymap. Ignored arguments are stored in the keymap with a value of klepto.NULL. Note that for class methods, it may be useful to ignore 'self'. The decorated function will gain new methods for working with cache keys - call: __call__ the function with the most recently provided arguments - valid: True if the most recently provided arguments are valid - key: get the cache key for the most recently provided arguments - keymap: get the registered keymap [default: klepto.keymaps.keymap] - register: register a new keymap The function is not evaluated until the 'call' method is called. Both generating the key and checking for validity avoid calling the function by inspecting the function's input signature. The default keymap is keymaps.keymap(flat=True). Alternate keymaps can be set with the 'register' method on the decorated function.""" # returns (*varargs, **kwds) where all info in kwds except varargs # however, special cases (builtins, etc) return (*args, **kwds) _map = kwds.get('keymap', None) if _map is None: _map = kleptokeymap() tol = kwds.get('tol', None) deep = kwds.get('deep', False) if deep: rounded = deep_round else: rounded = simple_round # enable rounding @rounded(tol) def rounded_args(*args, **kwds): return (args, kwds) def dec(f): _args = [(),{}] _keymap = [_map] #[kleptokeymap()] def last_args(): "get the most recently provided (*args, **kwds)" return _args[0],_args[1] def func(*args, **kwds): _args[0] = args _args[1] = kwds _map = _keymap[0] args,kwds = rounded_args(*args, **kwds) args,kwds = _keygen(f, ignored, *args, **kwds) return _map(*args, **kwds) def call(): "call func with the most recently provided (*args, **kwds)" ar,kw = last_args() return f(*ar,**kw) def valid(): "check if func(*args, **kwds) is valid (without calling the function)" ar,kw = last_args() return isvalid(f,*ar,**kw) #XXX: better validate? (raises errors) def key(): "get cache 'key' for most recently provided (*args, **kwds)" ar,kw = last_args() _map = _keymap[0] ar,kw = rounded_args(*ar, **kw) ar,kw = _keygen(f, ignored, *ar, **kw) #XXX: better lookup saved key? return _map(*ar, **kw) def register(mapper): "register a new keymap instance" if isinstance(mapper, type): mapper = mapper() if not isinstance(mapper, kleptokeymap): raise TypeError("'%s' is not a klepto keymap instance" % getattr(mapper,'__name__',mapper)) _keymap[0] = mapper return def keymap(): "get the registered keymap instance" return _keymap[0] func.__ignored__ = ignored func.__func__ = f func.__args__ = last_args func.call = call func.valid = valid func.key = key func.keymap = keymap func.register = register return func return dec