_introspection.py 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546
  1. """
  2. Python introspection helpers.
  3. """
  4. from types import CodeType as code, FunctionType as function
  5. def copycode(template, changes):
  6. if hasattr(code, "replace"):
  7. return template.replace(**{"co_" + k : v for k, v in changes.items()})
  8. names = [
  9. "argcount", "nlocals", "stacksize", "flags", "code", "consts",
  10. "names", "varnames", "filename", "name", "firstlineno", "lnotab",
  11. "freevars", "cellvars"
  12. ]
  13. if hasattr(code, "co_kwonlyargcount"):
  14. names.insert(1, "kwonlyargcount")
  15. if hasattr(code, "co_posonlyargcount"):
  16. # PEP 570 added "positional only arguments"
  17. names.insert(1, "posonlyargcount")
  18. values = [
  19. changes.get(name, getattr(template, "co_" + name))
  20. for name in names
  21. ]
  22. return code(*values)
  23. def copyfunction(template, funcchanges, codechanges):
  24. names = [
  25. "globals", "name", "defaults", "closure",
  26. ]
  27. values = [
  28. funcchanges.get(name, getattr(template, "__" + name + "__"))
  29. for name in names
  30. ]
  31. return function(copycode(template.__code__, codechanges), *values)
  32. def preserveName(f):
  33. """
  34. Preserve the name of the given function on the decorated function.
  35. """
  36. def decorator(decorated):
  37. return copyfunction(decorated,
  38. dict(name=f.__name__), dict(name=f.__name__))
  39. return decorator