def _is_empty_function(func, unwrap=False):
""" Return True if func is considered empty.
All functions with no return statement have an implicit return None - this is explicit in the code object.
"""
if isinstance(func, (staticmethod, classmethod, types.MethodType)):
func = six.get_method_function(func)
if isinstance(func, property):
func = property.fget
if unwrap:
func = _unwrap_function(func)
try:
code_obj = six.get_function_code(func)
except AttributeError:
# This callable is something else - assume it is OK.
return True
# quick check
if code_obj.co_code == b'd\x00\x00S' and code_obj.co_consts[0] is None:
return True
if code_obj.co_code == b'd\x01\x00S' and code_obj.co_consts[1] is None:
return True
# convert bytes to instructions
instructions = _get_instructions(code_obj)
if len(instructions) < 2:
return True # this never happens as there is always the implicit return None which is 2 instructions
assert instructions[-1].opname == 'RETURN_VALUE' # returns TOS (top of stack)
instruction = instructions[-2]
if not (instruction.opname == 'LOAD_CONST' and code_obj.co_consts[instruction.arg] is None): # TOS is None
return False # return is not None
instructions = instructions[:-2]
if len(instructions) == 0:
return True
# look for raise NotImplementedError
if instructions[-1].opname == 'RAISE_VARARGS':
# the thing we are raising should be the result of __call__ (instantiating exception object)
if instructions[-2].opname == 'CALL_FUNCTION':
for instr in instructions[:-2]:
if instr.opname == 'LOAD_GLOBAL' and code_obj.co_names[instr.arg] == 'NotImplementedError':
return True
return False
评论列表
文章目录