예제 #1
0
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
예제 #2
0
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