Skip to content

Instantly share code, notes, and snippets.

@thatbirdguythatuknownot
Created November 30, 2021 21:00
Show Gist options
  • Save thatbirdguythatuknownot/524234dbe8415f1873da57713fa0869c to your computer and use it in GitHub Desktop.
Save thatbirdguythatuknownot/524234dbe8415f1873da57713fa0869c to your computer and use it in GitHub Desktop.
Inner decorator
import types
import opcode
MAKE_FUNCTION = opcode.opmap['MAKE_FUNCTION']
del opcode
def decorate_inner(decorator, name):
def actual_decorator(outer_fn):
# Try and find the decorator function in co_consts,
# perform EAFP
co_consts = outer_fn.__code__.co_consts
try:
index = co_consts.index(decorator)
except ValueError:
index = len(co_consts)
outer_fn.__code__ = outer_fn.__code__.replace(
co_consts=co_consts + (decorator,)
)
# Try and find the name in co_consts,
# perform EAFP
try:
index2 = co_consts.index(
f"{outer_fn.__code__.co_name}.<locals>.{name}"
)
except ValueError:
raise RuntimeError(f"couldn't find name {name}") from None
if index2 > 127:
raise IndexError(f"name index in co_consts is > 127")
co_code = outer_fn.__code__.co_code
character = chr(index2)
base = co_code.find(f'd{character}'.encode())
while co_code[base+2] is not MAKE_FUNCTION:
base = co_code.find(f'd{character}'.encode(), base+2)
outer_fn.__code__ = outer_fn.__code__.replace(
co_code=(co_code[:base+4]
+ f'd{chr(index)}\x02\x00\x83\x01'.encode('l1')
+ co_code[base+4:])
)
return outer_fn
return actual_decorator
def deco(fn):
def wrapper(*args, **kwargs):
print("Calling", fn.__name__)
ret = fn()
print("Called", fn.__name__)
return ret
return wrapper
@decorate_inner(deco, "g")
def f():
def g():
return 42
return g
g = f()
print(g())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment