This repository has been archived by the owner on Feb 9, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
interface.py
138 lines (105 loc) · 4.73 KB
/
interface.py
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
##############################################################################
#
# Copyright (c) 2004 Zope Foundation 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.
#
##############################################################################
"""Interface Inspection Utilities
"""
import inspect
from zope.interface import Interface, providedBy
from zope.interface.interfaces import IInterface, ISpecification
from zope.interface.interfaces import IElement, IAttribute, IMethod
from zope.schema.interfaces import IField
from zope.apidoc.utilities import getPythonPath, renderText, getDocFormat
def getElements(iface, type=IElement):
"""Return a dictionary containing the elements in an interface.
The type specifies whether we are looking for attributes or methods."""
items = {}
for name in iface:
attr = iface[name]
if type.providedBy(attr):
items[name] = attr
return items
def getFieldsInOrder(iface, _itemkey=lambda x: x[1].order):
"""Return a list of (name, field) tuples in native interface order."""
return sorted(getElements(iface, IField).items(), key=_itemkey)
def getAttributes(iface):
"""Returns a list of attributes specified in the interface."""
return [(name, attr)
for name, attr in getElements(iface, IAttribute).items()
if not (IField.providedBy(attr) or IMethod.providedBy(attr))]
def getMethods(iface):
"""Returns a list of methods specified in the interface."""
return getElements(iface, IMethod).items()
def getFields(iface):
"""Returns a list of fields specified in the interface."""
return getFieldsInOrder(iface)
def getInterfaceTypes(iface):
"""Return a list of interface types that are specified for this
interface.
Note that you should only expect one type at a time.
"""
types = list(providedBy(iface).flattened())
# Remove interfaces provided by every interface instance
types.remove(ISpecification)
types.remove(IElement)
types.remove(Interface)
# Remove interface provided by every interface type
types.remove(IInterface)
return types
def getFieldInterface(field):
"""Return the interface representing the field."""
name = field.__class__.__name__
field_iface = None
ifaces = tuple(providedBy(field).flattened())
for iface in ifaces:
# All field interfaces implement `IField`. In case the name match
# below does not work, use the first `IField`-based interface found
if field_iface is None and iface.extends(IField):
field_iface = iface
# Usually fields have interfaces with the same name (with an 'I')
if iface.getName() == 'I' + name:
return iface
# If not even a `IField`-based interface was found, return the first
# interface of the implemented interfaces list.
return field_iface or ifaces[0]
def _getDocFormat(attr):
module = inspect.getmodule(attr.interface)
return getDocFormat(module)
def getAttributeInfoDictionary(attr, format=None):
"""Return a page-template-friendly information dictionary."""
format = format or _getDocFormat(attr)
return {'name': attr.getName(),
'doc': renderText(attr.getDoc() or u'', format=format)}
def getMethodInfoDictionary(method, format=None):
"""Return a page-template-friendly information dictionary."""
format = format or _getDocFormat(method)
return {'name': method.getName(),
'signature': method.getSignatureString(),
'doc': renderText(method.getDoc() or u'', format=format)}
def getFieldInfoDictionary(field, format=None):
"""Return a page-template-friendly information dictionary."""
format = format or _getDocFormat(field)
info = {'name': field.getName(),
'required': field.required,
'required_string': field.required and u'required' or u'optional',
'default': repr(field.default),
'title': field.title}
# Determine the interface of the field
iface = getFieldInterface(field)
info['iface'] = {'name': iface.getName(), 'id': getPythonPath(iface)}
# Determine the field class
class_ = field.__class__
info['class'] = {'name': class_.__name__,
'path': getPythonPath(class_).replace('.', '/')}
# Render the field description
info['description'] = renderText(field.description or u'', format=format)
return info