##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Method interfaces
 
Revision information:
$Id: Method.py 40218 2005-11-18 14:39:19Z andreasjung $
"""
import Exceptions
from Attribute import Attribute
 
sig_traits = ['positional', 'required', 'optional', 'varargs', 'kwargs']
 
CO_VARARGS = 4
CO_VARKEYWORDS = 8
 
class Method(Attribute):
    """Method interfaces
 
    The idea here is that you have objects that describe methods.
    This provides an opportunity for rich meta-data.
    """
 
    # We can't say this yet because we don't have enough
    # infrastructure in place.
    #
    #__implements__ = IMethod
 
    interface=''
 
    def __call__(self, *args, **kw):
        raise Exceptions.BrokenImplementation(self.interface, self.__name__)
 
    def getSignatureInfo(self):
        info = {}
        for t in sig_traits:
            info[t] = getattr(self, t)
 
        return info
 
    def getSignatureString(self):
        sig = "("
        for v in self.positional:
            sig = sig + v
            if v in self.optional.keys():
                sig = sig + "=%s" % `self.optional[v]`
            sig = sig + ", "
        if self.varargs:
            sig = sig + ("*%s, " % self.varargs)
        if self.kwargs:
            sig = sig + ("**%s, " % self.kwargs)
 
        # slice off the last comma and space
        if self.positional or self.varargs or self.kwargs:
            sig = sig[:-2]
 
        sig = sig + ")"
        return sig
 
 
def fromFunction(func, interface='', imlevel=0):
    m=Method(func.__name__, func.__doc__)
    defaults=func.func_defaults or ()
    c=func.func_code
    na=c.co_argcount-imlevel
    names=c.co_varnames[imlevel:]
    d={}
    nr=na-len(defaults)
    if nr < 0:
        defaults=defaults[-nr:]
        nr=0
 
    for i in range(len(defaults)):
        d[names[i+nr]]=defaults[i]
 
    m.positional=names[:na]
    m.required=names[:nr]
    m.optional=d
 
    argno = na
    if c.co_flags & CO_VARARGS:
        m.varargs = names[argno]
        argno = argno + 1
    else:
        m.varargs = None
    if c.co_flags & CO_VARKEYWORDS:
        m.kwargs = names[argno]
    else:
        m.kwargs = None
 
    m.interface=interface
    return m
 
def fromMethod(meth, interface=''):
    func = meth.im_func
    return fromFunction(func, interface, imlevel=1)