On 03/04/2013 02:05, Rotwang wrote:
[...]

After thinking about it for a while I've come up with the following
abomination:

import inspect

def sigwrapper(sig):
   if not isinstance(sig, inspect.Signature):
     sig = inspect.signature(sig)
   def wrapper(f):
     ps = 'args = []\n\t\t'
     ks = 'kwargs = {}\n\t\t'
     for p in sig.parameters.values():
       if p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD):
         ps = '%sargs.append(%s)\n\t\t' % (ps, p.name)
       elif p.kind == p.VAR_POSITIONAL:
         ps = '%sargs.extend(%s)\n\t\t' % (ps, p.name)
       elif p.kind == p.KEYWORD_ONLY:
         ks = '%skwargs[%r] = %s\n\t\t' % (ks, p.name, p.name)
       elif p.kind == p.VAR_KEYWORD:
         ks = '%skwargs.update(%s)\n\t\t' % (ks, p.name)
     loc = {'wrapped': f}
     defstring = ('def wrapouter(wrapped = wrapped):'
                  '\n\tdef wrapinner%s:'
                  '\n\t\t%s%sreturn wrapped(*args, **kwargs)'
                  '\n\treturn wrapinner' % (sig, ps, ks))
     exec(defstring, f.__globals__, loc)
     return loc['wrapouter']()
   return wrapper

Oops! Earlier I found out the hard way that this fails when the decorated function has arguments called 'args' or 'kwargs'. Here's a modified version that fixes said bug, but presumably not the many others I haven't noticed yet:

def sigwrapper(sig):
  if not isinstance(sig, inspect.Signature):
    sig = inspect.signature(sig)
  n = 0
  while True:
    pn = 'p_%i' % n
    kn = 'k_%i' % n
    if pn not in sig.parameters and kn not in sig.parameters:
      break
    n += 1
  ps = '%s = []\n\t\t' % pn
  ks = '%s = {}\n\t\t' % kn
  for p in sig.parameters.values():
    if p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD):
      ps = '%s%s.append(%s)\n\t\t' % (ps, pn, p.name)
    elif p.kind == p.VAR_POSITIONAL:
      ps = '%s%s.extend(%s)\n\t\t' % (ps, pn, p.name)
    elif p.kind == p.KEYWORD_ONLY:
      ks = '%s%s[%r] = %s\n\t\t' % (ks, kn, p.name, p.name)
    elif p.kind == p.VAR_KEYWORD:
      ks = '%s%s.update(%s)\n\t\t' % (ks, kn, p.name)
  defstring = ('def wrapouter(wrapped = wrapped):'
               '\n\tdef wrapinner%s:'
               '\n\t\t%s%sreturn wrapped(*%s, **%s)'
               '\n\treturn wrapinner' % (sig, ps, ks, pn, kn))
  def wrapper(f):
    loc = {'wrapped': f}
    exec(defstring, f.__globals__, loc)
    return loc['wrapouter']()
  return wrapper
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to