#!/usr/bin/env python
# Copyright (c) 2001-2002, MetaSlash Inc. All rights reserved.
"""
Object to hold information about functions.
Also contain a pseudo Python function object
"""
import string
_ARGS_ARGS_FLAG = 4
_KW_ARGS_FLAG = 8
_CO_FLAGS_MASK = _ARGS_ARGS_FLAG + _KW_ARGS_FLAG
class _ReturnValues:
def __init__(self):
self.returnValues = None
def returnsNoValue(self):
returnValues = self.returnValues
# if unset, we don't know
if returnValues is None:
return 0
# it's an empty list, that means no values
if not returnValues:
return 1
# make sure each value is not None
for rv in returnValues:
if not rv[1].isNone():
return 0
return returnValues[-1][1].isImplicitNone()
class FakeCode :
"This is a holder class for code objects (so we can modify them)"
def __init__(self, code, varnames = None) :
for attr in dir(code):
try:
setattr(self, attr, getattr(code, attr))
except:
pass
if varnames is not None:
self.co_varnames = varnames
class FakeFunction(_ReturnValues):
"This is a holder class for turning code at module level into a function"
def __init__(self, name, code, func_globals = {}, varnames = None) :
_ReturnValues.__init__(self)
self.func_name = self.__name__ = name
self.func_doc = self.__doc__ = "ignore"
self.func_code = FakeCode(code, varnames)
self.func_defaults = None
self.func_globals = func_globals
def __str__(self):
return self.func_name
def __repr__(self):
return '%s from %r' % (self.func_name, self.func_code.co_filename)
class Function(_ReturnValues):
"Class to hold all information about a function"
def __init__(self, function, isMethod=0):
_ReturnValues.__init__(self)
self.function = function
self.isMethod = isMethod
self.minArgs = self.maxArgs = function.func_code.co_argcount
if function.func_defaults is not None :
self.minArgs = self.minArgs - len(function.func_defaults)
# if function uses *args, there is no max # args
try:
if function.func_code.co_flags & _ARGS_ARGS_FLAG != 0 :
self.maxArgs = None
self.supportsKW = function.func_code.co_flags & _KW_ARGS_FLAG
except AttributeError:
# this happens w/Zope
self.supportsKW = 0
def __str__(self):
return self.function.func_name
def __repr__(self):
return '%s from %r:%d' % (self.function.func_name,
self.function.func_code.co_filename,
self.function.func_code.co_firstlineno)
def arguments(self) :
numArgs = self.function.func_code.co_argcount
if self.maxArgs is None :
numArgs = numArgs + 1
if self.supportsKW :
numArgs = numArgs + 1
return self.function.func_code.co_varnames[:numArgs]
def isParam(self, name) :
return name in self.arguments()
def isStaticMethod(self):
return self.isMethod and isinstance(self.function, type(create_fake))
def isClassMethod(self):
try:
return self.isMethod and self.function.im_self is not None
except AttributeError:
return 0
def defaultValue(self, name) :
func_code = self.function.func_code
arg_names = list(func_code.co_varnames[:func_code.co_argcount])
i = arg_names.index(name)
if i < self.minArgs :
raise ValueError
return self.function.func_defaults[i - self.minArgs]
def varArgName(self) :
if self.maxArgs is not None :
return None
func_code = self.function.func_code
return func_code.co_varnames[func_code.co_argcount]
def create_fake(name, code, func_globals = {}, varnames = None) :
return Function(FakeFunction(name, code, func_globals, varnames))
def create_from_file(file, filename, module) :
if file is None:
return create_fake(filename, compile('', filename, 'exec'))
# Make sure the file is at the beginning
# if python compiled the file, it will be at the end
file.seek(0)
# Read in the source file, see py_compile.compile() for games w/src str
codestr = file.read()
codestr = string.replace(codestr, "\r\n", "\n")
codestr = string.replace(codestr, "\r", "\n")
if codestr and codestr[-1] != '\n' :
codestr = codestr + '\n'
code = compile(codestr, filename, 'exec')
return Function(FakeFunction('__main__', code, module.__dict__))
def _co_flags_equal(o1, o2) :
return (o1.co_flags & _CO_FLAGS_MASK) == (o2.co_flags & _CO_FLAGS_MASK)
def same_signature(func, object) :
'''Return a boolean value if the <func> has the same signature as
a function with the same name in <object> (ie, an overriden method)'''
try :
baseMethod = getattr(object, func.func_name)
base_func_code = baseMethod.im_func.func_code
except AttributeError :
return 1
return _co_flags_equal(base_func_code, func.func_code) and \
base_func_code.co_argcount == func.func_code.co_argcount
|