File: InterfaceTool.py

package info (click to toggle)
zope-cmfplone 2.5.1-4etch3
  • links: PTS
  • area: main
  • in suites: etch
  • size: 7,752 kB
  • ctags: 5,237
  • sloc: python: 28,264; xml: 3,723; php: 129; makefile: 99; sh: 2
file content (188 lines) | stat: -rw-r--r-- 6,446 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
from types import ModuleType, ListType, TupleType
from Products.CMFPlone.interfaces.InterfaceTool import IInterfaceTool \
     as z2IInterfaceTool
from Products.CMFPlone.interfaces import IInterfaceTool
from Acquisition import aq_base
from Products.CMFCore.utils import UniqueObject
from OFS.SimpleItem import SimpleItem
from Globals import InitializeClass
from AccessControl import ClassSecurityInfo
from Products.CMFPlone.PloneBaseTool import PloneBaseTool

from Interface.Implements import getImplements, flattenInterfaces
from Interface import Interface
from Interface.IMethod import IMethod

from zope.interface import implements

_marker = ('module_finder',)

class InterfaceTool(PloneBaseTool, UniqueObject, SimpleItem):
    """ This tool exposes the interface package for TTW applications,
    by accepting a dotted name of an interface and exporting the
    IInterface API """

    __implements__ = (PloneBaseTool.__implements__, z2IInterfaceTool,
                      SimpleItem.__implements__, )

    implements(IInterfaceTool)

    id = 'portal_interface'
    meta_type= 'Portal Interface Tool'
    security = ClassSecurityInfo()

    security.declarePublic('objectImplements')
    def objectImplements(self, obj, dotted_name):
        """ Asserts if an object implements a given interface """
        obj = aq_base(obj)
        iface = resolveInterface(dotted_name)
        return iface.isImplementedBy(obj)

    security.declarePublic('classImplements')
    def classImplements(self, obj, dotted_name):
        """ Asserts if an object's class implements a given interface """
        klass = aq_base(obj).__class__
        iface = resolveInterface(dotted_name)
        return iface.isImplementedBy(klass)

    security.declarePublic('namesAndDescriptions')
    def namesAndDescriptions(self, dotted_name, all=0):
        """ Returns a list of pairs (name, description) for a given
        interface"""
        iface = resolveInterface(dotted_name)
        nd = iface.namesAndDescriptions(all=all)
        return [(n, d.getDoc()) for n, d in nd]

    security.declarePublic('getInterfacesOf')
    def getInterfacesOf(self, object):
        """Returns the list of interfaces which are implemented by the object
        """
        impl = getImplements(object)
        if impl:
            if type(impl) in (ListType, TupleType):
                result = flattenInterfaces(impl)
            else:
                result = (impl, )
            return [ iface for iface in result if iface is not Interface ]

    def getBaseInterfacesOf(self, object):
        """Returns all base interfaces of an object but no direct interfaces

        Base interfaces are the interfaces which are the super interfaces of the
        direct interfaces
        """
        ifaces = self.getInterfacesOf(object)
        bases = []
        for iface in ifaces:
            visitBaseInterfaces(iface, bases)
        return [biface for biface in bases if biface not in ifaces ]

    def getInterfaceInformations(self, iface):
        """Gets all useful informations from an iface

        * name
        * dotted name
        * trimmed doc string
        * base interfaces
        * methods with signature and trimmed doc string
        * attributes with trimemd doc string
        """
        bases = [ base for base in iface.getBases() if base is not Interface ]

        attributes = []
        methods = []
        for name, desc in iface.namesAndDescriptions():
            if IMethod.isImplementedBy(desc):
                methods.append({'signature' : desc.getSignatureString(),
                                'name' : desc.getName(),
                                'doc' : _trim_doc_string(desc.getDoc()),
                               })
            else:
                attributes.append({'name' : desc.getName(),
                                   'doc' : _trim_doc_string(desc.getDoc()),
                                  })

        result = {
            'name' : iface.getName(),
            'dotted_name' : getDottedName(iface),
            'doc' : _trim_doc_string(desc.getDoc()),
            'bases' : bases,
            'base_names' : [getDottedName(iface) for base in bases ],
            'attributes' : attributes,
            'methods' : methods,
            }

        return result

def resolveInterface(dotted_name):
    parts = dotted_name.split('.')
    m_name = '.'.join(parts[:-1])
    k_name = parts[-1]
    module = __import__(m_name, globals(), locals(), [k_name])
    klass = getattr(module, k_name)
    if not issubclass(klass, Interface):
        raise ValueError, '%r is not a valid Interface.' % dotted_name
    return klass

def getDottedName(iface):
    return "%s.%s" % (iface.__module__, iface.__name__)

def _trim_doc_string(text):
    """
    Trims a doc string to make it format
    correctly with structured text.
    """
    text = text.strip().replace('\r\n', '\n')
    lines = text.split('\n')
    nlines = [lines[0]]
    if len(lines) > 1:
        min_indent=None
        for line in lines[1:]:
            indent=len(line) - len(line.lstrip())
            if indent < min_indent or min_indent is None:
                min_indent=indent
        for line in lines[1:]:
            nlines.append(line[min_indent:])
    return '\n'.join(nlines)

def visitBaseInterfaces(iface, lst):
    bases = iface.getBases()
    for base in bases:
        if base is Interface or base in lst:
            return
        lst.append(base)
        visitBaseInterfaces(iface, lst)

class InterfaceFinder:

    _visited = {}
    _found = {}

    def findInterfaces(self, n=None, module=_marker):
        # return class reference info
        dict={}
        pairs = []
        if module is _marker:
            import Products
            module = Products
        self._visited[module] = None
        for sym in dir(module):
            ob=getattr(module, sym)
            if type(ob) is type(Interface) and \
               issubclass(ob, Interface) and \
               ob is not Interface:
                self.found(ob)
            elif type(ob) is ModuleType and ob not in self._visited.keys():
                self.findInterfaces(module=ob)

        ifaces = self._found.keys()
        ifaces.sort()
        ifaces.reverse()
        if n is not None:
            ifaces = ifaces[:n]
        return ifaces

    def found(self, iface):
        self._found[getDottedName(iface)] = iface

InitializeClass(InterfaceTool)