Example #1
0
 def callable_info(cls, f):
   '''Info about a callable.
   
   The results are cached for efficiency.
   
   :param f:
   :type  f: callable
   :rtype: frozendict
   '''
   if not callable(f):
     return None
   
   if isinstance(f, FunctionType):
     # in case of ensure_va_kwa
     try:
       f = f.wrapped_func
     except AttributeError:
       pass
   
   cache_key = callable_cache_key(f)
   
   try:
     return cls._info_cache[cache_key]
   except KeyError:
     pass
   
   is_method, args, varargs, varkw, defaults = cls.getargspec(f)
   
   _args = []
   args_len = len(args)
   defaults_len = 0
   
   if defaults is not None:
     defaults_len = len(defaults)
   
   for i,n in enumerate(args):
     default_index = i-(args_len-defaults_len)
     v = Undefined
     if default_index > -1:
       v = defaults[default_index]
     _args.append((n, v))
   
   info = frozendict({
     'name':f.func_name,
     'args':tuple(_args),
     'varargs':bool(varargs),
     'varkw':bool(varkw),
     'method':is_method
   })
   
   cls._info_cache[cache_key] = info
   return info
Example #2
0
 def ensure_va_kwa(cls, f, parent=None):
   '''Ensures `f` accepts both ``*varargs`` and ``**kwargs``.
   
   If `f` does not support ``*args``, it will be wrapped with a
   function which cuts away extra arguments in ``*args``.
   
   If `f` does not support ``*args``, it will be wrapped with a
   function which discards the ``**kwargs``.
   
   :param f:
   :type  f:       callable
   :param parent:  The parent on which `f` is defined. If specified, we will perform
                   ``parent.<name of f> = wrapper`` in the case we needed to wrap `f`.
   :type  parent:  object
   :returns: A callable which is guaranteed to accept both ``*args`` and ``**kwargs``.
   :rtype: callable
   '''
   is_method, args, varargs, varkw, defaults = cls.getargspec(f)
   va_kwa_wrapper = None
   
   if varargs is None and varkw is None:
     if args:
       def va_kwa_wrapper(*va, **kw):
         kws = kw.copy()
         for k in kw:
           if k not in args:
             del kws[k]
         return f(*va[:len(args)], **kws)
     else:
       def va_kwa_wrapper(*va, **kw):
         return f()
   elif varargs is None:
     if args:
       def va_kwa_wrapper(*va, **kw):
         return f(*va[:len(args)], **kw)
     else:
       def va_kwa_wrapper(*va, **kw):
         return f(**kw)
   elif varkw is None:
     if args:
       def va_kwa_wrapper(*va, **kw):
         kws = kw.copy()
         for k in kw:
           if k not in args:
             del kws[k]
         return f(*va, **kw)
     else:
       def va_kwa_wrapper(*va, **kw):
         return f(*va)
   
   if va_kwa_wrapper:
     va_kwa_wrapper.info = frozendict(cls.callable_info(f).update({
       'varargs': True,
       'varkw': True
     }))
     cls._info_cache[callable_cache_key(f)] = va_kwa_wrapper.info
     va_kwa_wrapper.wrapped_func = f
     va_kwa_wrapper.im_func = f
     va_kwa_wrapper.__name__ = f.__name__
     try:
       va_kwa_wrapper.im_class = f.im_class
     except AttributeError:
       pass
     for k in dir(f):
       if k[0] != '_' or k in ('__name__'):
         setattr(va_kwa_wrapper, k, getattr(f, k))
     if parent is not None:
       setattr(parent, info['name'], va_kwa_wrapper)
     return va_kwa_wrapper
   return f