_introspection.py 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  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",
  10. "nlocals",
  11. "stacksize",
  12. "flags",
  13. "code",
  14. "consts",
  15. "names",
  16. "varnames",
  17. "filename",
  18. "name",
  19. "firstlineno",
  20. "lnotab",
  21. "freevars",
  22. "cellvars",
  23. ]
  24. if hasattr(code, "co_kwonlyargcount"):
  25. names.insert(1, "kwonlyargcount")
  26. if hasattr(code, "co_posonlyargcount"):
  27. # PEP 570 added "positional only arguments"
  28. names.insert(1, "posonlyargcount")
  29. values = [changes.get(name, getattr(template, "co_" + name)) for name in names]
  30. return code(*values)
  31. def copyfunction(template, funcchanges, codechanges):
  32. names = [
  33. "globals",
  34. "name",
  35. "defaults",
  36. "closure",
  37. ]
  38. values = [
  39. funcchanges.get(name, getattr(template, "__" + name + "__")) for name in names
  40. ]
  41. return function(copycode(template.__code__, codechanges), *values)
  42. def preserveName(f):
  43. """
  44. Preserve the name of the given function on the decorated function.
  45. """
  46. def decorator(decorated):
  47. return copyfunction(decorated, dict(name=f.__name__), dict(name=f.__name__))
  48. return decorator