# -*- python -*-
#
# OpenAlea.Core
#
# Copyright 2006-2009 INRIA - CIRAD - INRA
#
# File author(s): Samuel Dufour-Kowalski <samuel.dufour@sophia.inria.fr>
# Christophe Pradal <christophe.prada@cirad.fr>
#
# Distributed under the Cecill-C License.
# See accompanying file LICENSE.txt or copy at
# http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html
#
# OpenAlea WebSite : http://openalea.gforge.inria.fr
#
###############################################################################
"""Signature class that instropect python functor based on the code"""
__license__ = "Cecill-C"
__revision__ = " $Id$ "
import inspect
import types
import re
import traceback
import copy
from openalea.core.interface import TypeInterfaceMap
[docs]class Signature(object):
"""Object to represent the signature of a function/method.
:param f: a function object containing __name__ variable
"""
def __init__(self, f):
""" f is a function object or instance method,
functor class are managed but need to be tested more carefully"""
if isinstance(f, dict): #recreate from serialised
self.name = f.get("name")
self.f_doc = f.get("f_doc")
self.parameters = f.get("parameters", [])
self.varargs = f.get("varargs", False)
self.keywords = f.get("keywords", False)
self.isMethod = f.get("isMethod", False)
self.isValid = f.get("isValid", True)
elif isinstance(f, Signature): #copy contructor
self.name = f.name
self.f_doc = f.f_doc
self.parameters = copy.deepcopy(f.parameters)
self.varargs = f.varargs
self.keywords = f.keywords
self.isMethod = f.isMethod
self.isValid = f.isValid
else: #normal function inspection
self.name = f.__name__
self.f_doc = inspect.getdoc(f)
self.parameters = []
self.varargs = None
self.keywords = None
self.isMethod = False
self.isValid = True
try:
# -- inspect the callable
args, defaults, varargs, keywords, self.isMethod = Signature.get_callable_arguments(f)
# -- the signature might have not been resolved
# however, we might not want to raise an exception
# so we put the isValid flag to false and stop the init.
if args==defaults==varargs==keywords==self.isMethod==-1:
self.isValid = False
return
# -- create a set out of the default arg names for later reference
defaultArgNames = [] if len(defaults)==0 else set(zip(*defaults)[0])
# -- create parameters that do not have defaults (not in defaultArgNames)
for arg in args:
if arg not in defaultArgNames:
self.parameters.append(dict(name=arg, interface=None,
value=None))
# -- create parameters that have defaults
for arg, val in defaults:
interface = TypeInterfaceMap().get(type(val), None)
self.parameters.append(dict(name=arg, interface=interface,
value=val))
# -- do we have varargs? (*args)
if varargs is not None:
self.varargs = {"varargs":arg, "interface": "ISequence", "value":[]}
# -- do we have keyword args? (**kwargs)
if keywords is not None:
self.keywords = {"keywords":arg, "interface":"IDict","value":{}}
except Exception, e:
traceback.print_exc()
def __repr__(self):
return "{'name':" +repr(self.name) +", " + \
"'f_doc':" +repr(self.f_doc) +", " + \
"'parameters':" +repr(self.parameters) +", " + \
"'varargs':" +repr(self.varargs) +", " + \
"'keywords':" +repr(self.keywords) +", " + \
"'isMethod':" +repr(self.isMethod) +", " + \
"'isValid':" +repr(self.isValid) +"}"
[docs] def get_name(self):
return self.name
[docs] def get_doc(self):
return self.f_doc
[docs] def get_parameters(self, eludeSelf=True):
if eludeSelf and self.isMethod:
return self.parameters[1:]
else:
return self.parameters[:]
[docs] def get_returns(self):
""" Return the outputs of a functor based on a predifened contract.
TO BE DEFINED
TODO
"""
return dict(name="out", interface=None),
[docs] def get_varargs(self):
return self.varargs
[docs] def get_keywords(self):
return self.keywords
[docs] def get_all_parameters(self, eludeSelf=True):
params = self.get_parameters(eludeSelf=eludeSelf)
if self.varargs:
params += [self.varargs]
if self.keywords:
params += [self.keywords]
return params
@staticmethod
[docs] def get_callable_arguments(function):
""" Static method that returns 5 values for one entry object which can be
any callable. The returned 5-uple is as follows:
0 - list-of-simple-arguments. Can be an empty list.
1 - list-of-(argname,argvalue)-arguments-with-defaults. Can be an empty list.
2 - name-of-vararg-argument. Can be None.
3 - name-of-keyword-argument. Can be None.
5 - boolean : True if function is a method, False otherwise...
For Python defined callables, uses the "inspect" module. For builtins, tries
some regexp parsing of the docstring.
"""
isMethod = inspect.ismethod(function)
if isMethod or inspect.isfunction(function):
argspec = inspect.getargspec(function)
if argspec.defaults:
ndefs = len(argspec.defaults)
args = argspec.args[:-ndefs]
defaults = zip(argspec.args[-ndefs:], argspec.defaults)
else:
args = argspec.args
defaults = []
return args, defaults, argspec.varargs, argspec.keywords, isMethod
elif inspect.isbuiltin(function):
# builtins have no argument description
# we can only try to do some rough docstring parsing.
args, defaults, varargs, keywords = Signature.regexp_args(function)
return args, defaults, varargs, keywords, False
elif inspect.isclass(function) and "__call__" in function.__dict__:
func = function.__call__
return Signature.get_callable_arguments(func)
elif isinstance(function, types.InstanceType) and "__call__" in function.__dict__:
func = function.__call__
return Signature.get_callable_arguments(func)
else:
return -1,-1,-1,-1,-1
@staticmethod
[docs] def regexp_args(function):
assert inspect.isbuiltin(function)
name = function.__name__
re_str = r"\s*.*"+name+r"\s*\(([(){}\[\]a-zA-Z0-9*='\",\s]*)\).*"
m = re.match(re_str, inspect.getdoc(function))
args, defaults, varargs, keywords = [], [], None, None
if m is not None:
prototype = [ s.strip() for s in m.groups()[0].split(",") ]
for arg in prototype:
if "=" in arg:
n,v = arg.split("=")
try:
v = eval(v)
except:
pass
defaults.append([n,v])
elif len(arg)>0:
starCount = arg.count("*")
if starCount == 0:
args.append(arg)
elif starCount == 1:
varargs = arg
elif starCount == 2:
keywords = arg
else:
raise Exception("Unknown argument type : "+arg)
return args, defaults, varargs, keywords