~justin-fathomdb/nova/justinsb-openstack-api-volumes

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/twisted/python/components.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- test-case-name: twisted.python.test.test_components -*-
 
2
# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
 
3
# See LICENSE for details.
 
4
 
 
5
 
 
6
"""
 
7
Component architecture for Twisted, based on Zope3 components.
 
8
 
 
9
Using the Zope3 API directly is strongly recommended. Everything
 
10
you need is in the top-level of the zope.interface package, e.g.::
 
11
 
 
12
   from zope.interface import Interface, implements
 
13
 
 
14
   class IFoo(Interface):
 
15
       pass
 
16
 
 
17
   class Foo:
 
18
       implements(IFoo)
 
19
 
 
20
   print IFoo.implementedBy(Foo) # True
 
21
   print IFoo.providedBy(Foo()) # True
 
22
 
 
23
L{twisted.python.components.registerAdapter} from this module may be used to
 
24
add to Twisted's global adapter registry. 
 
25
 
 
26
L{twisted.python.components.proxyForInterface} is a factory for classes
 
27
which allow access to only the parts of another class defined by a specified
 
28
interface.
 
29
"""
 
30
 
 
31
# system imports
 
32
import warnings
 
33
 
 
34
# zope3 imports
 
35
from zope.interface import interface, declarations
 
36
from zope.interface.adapter import AdapterRegistry
 
37
 
 
38
# twisted imports
 
39
from twisted.python import reflect
 
40
from twisted.persisted import styles
 
41
 
 
42
 
 
43
class ComponentsDeprecationWarning(DeprecationWarning):
 
44
    """
 
45
    Nothing emits this warning anymore.
 
46
    """
 
47
 
 
48
 
 
49
# Twisted's global adapter registry
 
50
globalRegistry = AdapterRegistry()
 
51
 
 
52
# Attribute that registerAdapter looks at. Is this supposed to be public?
 
53
ALLOW_DUPLICATES = 0
 
54
 
 
55
# Define a function to find the registered adapter factory, using either a
 
56
# version of Zope Interface which has the `registered' method or an older
 
57
# version which does not.
 
58
if getattr(AdapterRegistry, 'registered', None) is None:
 
59
    def _registered(registry, required, provided):
 
60
        """
 
61
        Return the adapter factory for the given parameters in the given
 
62
        registry, or None if there is not one.
 
63
        """
 
64
        return registry.get(required).selfImplied.get(provided, {}).get('')
 
65
else:
 
66
    def _registered(registry, required, provided):
 
67
        """
 
68
        Return the adapter factory for the given parameters in the given
 
69
        registry, or None if there is not one.
 
70
        """
 
71
        return registry.registered([required], provided)
 
72
 
 
73
 
 
74
def registerAdapter(adapterFactory, origInterface, *interfaceClasses):
 
75
    """Register an adapter class.
 
76
 
 
77
    An adapter class is expected to implement the given interface, by
 
78
    adapting instances implementing 'origInterface'. An adapter class's
 
79
    __init__ method should accept one parameter, an instance implementing
 
80
    'origInterface'.
 
81
    """
 
82
    self = globalRegistry
 
83
    assert interfaceClasses, "You need to pass an Interface"
 
84
    global ALLOW_DUPLICATES
 
85
 
 
86
    # deal with class->interface adapters:
 
87
    if not isinstance(origInterface, interface.InterfaceClass):
 
88
        origInterface = declarations.implementedBy(origInterface)
 
89
 
 
90
    for interfaceClass in interfaceClasses:
 
91
        factory = _registered(self, origInterface, interfaceClass)
 
92
        if factory is not None and not ALLOW_DUPLICATES:
 
93
            raise ValueError("an adapter (%s) was already registered." % (factory, ))
 
94
    for interfaceClass in interfaceClasses:
 
95
        self.register([origInterface], interfaceClass, '', adapterFactory)
 
96
 
 
97
 
 
98
def getAdapterFactory(fromInterface, toInterface, default):
 
99
    """Return registered adapter for a given class and interface.
 
100
 
 
101
    Note that is tied to the *Twisted* global registry, and will
 
102
    thus not find adapters registered elsewhere.
 
103
    """
 
104
    self = globalRegistry
 
105
    if not isinstance(fromInterface, interface.InterfaceClass):
 
106
        fromInterface = declarations.implementedBy(fromInterface)
 
107
    factory = self.lookup1(fromInterface, toInterface)
 
108
    if factory is None:
 
109
        factory = default
 
110
    return factory
 
111
 
 
112
 
 
113
# add global adapter lookup hook for our newly created registry
 
114
def _hook(iface, ob, lookup=globalRegistry.lookup1):
 
115
    factory = lookup(declarations.providedBy(ob), iface)
 
116
    if factory is None:
 
117
        return None
 
118
    else:
 
119
        return factory(ob)
 
120
interface.adapter_hooks.append(_hook)
 
121
 
 
122
## backwardsCompatImplements and fixClassImplements should probably stick around for another
 
123
## release cycle. No harm doing so in any case.
 
124
 
 
125
def backwardsCompatImplements(klass):
 
126
    """DEPRECATED.
 
127
 
 
128
    Does nothing. Previously handled backwards compat from a
 
129
    zope.interface using class to a class wanting old twisted
 
130
    components interface behaviors.
 
131
    """
 
132
    warnings.warn("components.backwardsCompatImplements doesn't do anything in Twisted 2.3, stop calling it.", ComponentsDeprecationWarning, stacklevel=2)
 
133
 
 
134
def fixClassImplements(klass):
 
135
    """DEPRECATED.
 
136
 
 
137
    Does nothing. Previously converted class from __implements__ to
 
138
    zope implementation.
 
139
    """
 
140
    warnings.warn("components.fixClassImplements doesn't do anything in Twisted 2.3, stop calling it.", ComponentsDeprecationWarning, stacklevel=2)
 
141
 
 
142
 
 
143
def getRegistry():
 
144
    """Returns the Twisted global
 
145
    C{zope.interface.adapter.AdapterRegistry} instance.
 
146
    """
 
147
    return globalRegistry
 
148
 
 
149
# FIXME: deprecate attribute somehow?
 
150
CannotAdapt = TypeError
 
151
 
 
152
class Adapter:
 
153
    """I am the default implementation of an Adapter for some interface.
 
154
 
 
155
    This docstring contains a limerick, by popular demand::
 
156
 
 
157
        Subclassing made Zope and TR
 
158
        much harder to work with by far.
 
159
            So before you inherit,
 
160
            be sure to declare it
 
161
        Adapter, not PyObject*
 
162
 
 
163
    @cvar temporaryAdapter: If this is True, the adapter will not be
 
164
          persisted on the Componentized.
 
165
    @cvar multiComponent: If this adapter is persistent, should it be
 
166
          automatically registered for all appropriate interfaces.
 
167
    """
 
168
 
 
169
    # These attributes are used with Componentized.
 
170
 
 
171
    temporaryAdapter = 0
 
172
    multiComponent = 1
 
173
 
 
174
    def __init__(self, original):
 
175
        """Set my 'original' attribute to be the object I am adapting.
 
176
        """
 
177
        self.original = original
 
178
 
 
179
    def __conform__(self, interface):
 
180
        """
 
181
        I forward __conform__ to self.original if it has it, otherwise I
 
182
        simply return None.
 
183
        """
 
184
        if hasattr(self.original, "__conform__"):
 
185
            return self.original.__conform__(interface)
 
186
        return None
 
187
 
 
188
    def isuper(self, iface, adapter):
 
189
        """
 
190
        Forward isuper to self.original
 
191
        """
 
192
        return self.original.isuper(iface, adapter)
 
193
 
 
194
 
 
195
class Componentized(styles.Versioned):
 
196
    """I am a mixin to allow you to be adapted in various ways persistently.
 
197
 
 
198
    I define a list of persistent adapters.  This is to allow adapter classes
 
199
    to store system-specific state, and initialized on demand.  The
 
200
    getComponent method implements this.  You must also register adapters for
 
201
    this class for the interfaces that you wish to pass to getComponent.
 
202
 
 
203
    Many other classes and utilities listed here are present in Zope3; this one
 
204
    is specific to Twisted.
 
205
    """
 
206
 
 
207
    persistenceVersion = 1
 
208
 
 
209
    def __init__(self):
 
210
        self._adapterCache = {}
 
211
 
 
212
    def locateAdapterClass(self, klass, interfaceClass, default):
 
213
        return getAdapterFactory(klass, interfaceClass, default)
 
214
 
 
215
    def setAdapter(self, interfaceClass, adapterClass):
 
216
        self.setComponent(interfaceClass, adapterClass(self))
 
217
 
 
218
    def addAdapter(self, adapterClass, ignoreClass=0):
 
219
        """Utility method that calls addComponent.  I take an adapter class and
 
220
        instantiate it with myself as the first argument.
 
221
 
 
222
        @return: The adapter instantiated.
 
223
        """
 
224
        adapt = adapterClass(self)
 
225
        self.addComponent(adapt, ignoreClass)
 
226
        return adapt
 
227
 
 
228
    def setComponent(self, interfaceClass, component):
 
229
        """
 
230
        """
 
231
        self._adapterCache[reflect.qual(interfaceClass)] = component
 
232
 
 
233
    def addComponent(self, component, ignoreClass=0):
 
234
        """
 
235
        Add a component to me, for all appropriate interfaces.
 
236
 
 
237
        In order to determine which interfaces are appropriate, the component's
 
238
        provided interfaces will be scanned.
 
239
 
 
240
        If the argument 'ignoreClass' is True, then all interfaces are
 
241
        considered appropriate.
 
242
 
 
243
        Otherwise, an 'appropriate' interface is one for which its class has
 
244
        been registered as an adapter for my class according to the rules of
 
245
        getComponent.
 
246
 
 
247
        @return: the list of appropriate interfaces
 
248
        """
 
249
        for iface in declarations.providedBy(component):
 
250
            if (ignoreClass or
 
251
                (self.locateAdapterClass(self.__class__, iface, None)
 
252
                 == component.__class__)):
 
253
                self._adapterCache[reflect.qual(iface)] = component
 
254
 
 
255
    def unsetComponent(self, interfaceClass):
 
256
        """Remove my component specified by the given interface class."""
 
257
        del self._adapterCache[reflect.qual(interfaceClass)]
 
258
 
 
259
    def removeComponent(self, component):
 
260
        """
 
261
        Remove the given component from me entirely, for all interfaces for which
 
262
        it has been registered.
 
263
 
 
264
        @return: a list of the interfaces that were removed.
 
265
        """
 
266
        l = []
 
267
        for k, v in self._adapterCache.items():
 
268
            if v is component:
 
269
                del self._adapterCache[k]
 
270
                l.append(reflect.namedObject(k))
 
271
        return l
 
272
 
 
273
    def getComponent(self, interface, default=None):
 
274
        """Create or retrieve an adapter for the given interface.
 
275
 
 
276
        If such an adapter has already been created, retrieve it from the cache
 
277
        that this instance keeps of all its adapters.  Adapters created through
 
278
        this mechanism may safely store system-specific state.
 
279
 
 
280
        If you want to register an adapter that will be created through
 
281
        getComponent, but you don't require (or don't want) your adapter to be
 
282
        cached and kept alive for the lifetime of this Componentized object,
 
283
        set the attribute 'temporaryAdapter' to True on your adapter class.
 
284
 
 
285
        If you want to automatically register an adapter for all appropriate
 
286
        interfaces (with addComponent), set the attribute 'multiComponent' to
 
287
        True on your adapter class.
 
288
        """
 
289
        k = reflect.qual(interface)
 
290
        if self._adapterCache.has_key(k):
 
291
            return self._adapterCache[k]
 
292
        else:
 
293
            adapter = interface.__adapt__(self)
 
294
            if adapter is not None and not (
 
295
                hasattr(adapter, "temporaryAdapter") and
 
296
                adapter.temporaryAdapter):
 
297
                self._adapterCache[k] = adapter
 
298
                if (hasattr(adapter, "multiComponent") and
 
299
                    adapter.multiComponent):
 
300
                    self.addComponent(adapter)
 
301
            if adapter is None:
 
302
                return default
 
303
            return adapter
 
304
 
 
305
 
 
306
    def __conform__(self, interface):
 
307
        return self.getComponent(interface)
 
308
 
 
309
 
 
310
class ReprableComponentized(Componentized):
 
311
    def __init__(self):
 
312
        Componentized.__init__(self)
 
313
 
 
314
    def __repr__(self):
 
315
        from cStringIO import StringIO
 
316
        from pprint import pprint
 
317
        sio = StringIO()
 
318
        pprint(self._adapterCache, sio)
 
319
        return sio.getvalue()
 
320
 
 
321
 
 
322
 
 
323
def proxyForInterface(iface, originalAttribute='original'):
 
324
    """
 
325
    Create a class which proxies all method calls which adhere to an interface
 
326
    to another provider of that interface.
 
327
 
 
328
    This function is intended for creating specialized proxies. The typical way
 
329
    to use it is by subclassing the result::
 
330
 
 
331
      class MySpecializedProxy(proxyForInterface(IFoo)):
 
332
          def someInterfaceMethod(self, arg):
 
333
              if arg == 3:
 
334
                  return 3
 
335
              return self.original.someInterfaceMethod(arg)
 
336
 
 
337
    @param iface: The Interface to which the resulting object will conform, and
 
338
        which the wrapped object must provide.
 
339
 
 
340
    @param originalAttribute: name of the attribute used to save the original
 
341
        object in the resulting class. Default to C{original}.
 
342
    @type originalAttribute: C{str}
 
343
 
 
344
    @return: A class whose constructor takes the original object as its only
 
345
        argument. Constructing the class creates the proxy.
 
346
    """
 
347
    def __init__(self, original):
 
348
        setattr(self, originalAttribute, original)
 
349
    contents = {"__init__": __init__}
 
350
    for name in iface:
 
351
        contents[name] = _ProxyDescriptor(name, originalAttribute)
 
352
    proxy = type("(Proxy for %s)"
 
353
                 % (reflect.qual(iface),), (object,), contents)
 
354
    declarations.classImplements(proxy, iface)
 
355
    return proxy
 
356
 
 
357
 
 
358
 
 
359
class _ProxiedClassMethod(object):
 
360
    """
 
361
    A proxied class method.
 
362
 
 
363
    @ivar methodName: the name of the method which this should invoke when
 
364
        called.
 
365
    @type methodName: C{str}
 
366
 
 
367
    @ivar originalAttribute: name of the attribute of the proxy where the
 
368
        original object is stored.
 
369
    @type orginalAttribute: C{str}
 
370
    """
 
371
    def __init__(self, methodName, originalAttribute):
 
372
        self.methodName = methodName
 
373
        self.originalAttribute = originalAttribute
 
374
 
 
375
 
 
376
    def __call__(self, oself, *args, **kw):
 
377
        """
 
378
        Invoke the specified L{methodName} method of the C{original} attribute
 
379
        for proxyForInterface.
 
380
 
 
381
        @param oself: an instance of a L{proxyForInterface} object.
 
382
 
 
383
        @return: the result of the underlying method.
 
384
        """
 
385
        original = getattr(oself, self.originalAttribute)
 
386
        actualMethod = getattr(original, self.methodName)
 
387
        return actualMethod(*args, **kw)
 
388
 
 
389
 
 
390
 
 
391
class _ProxyDescriptor(object):
 
392
    """
 
393
    A descriptor which will proxy attribute access, mutation, and
 
394
    deletion to the L{original} attribute of the object it is being accessed
 
395
    from.
 
396
 
 
397
    @ivar attributeName: the name of the attribute which this descriptor will
 
398
        retrieve from instances' C{original} attribute.
 
399
    @type attributeName: C{str}
 
400
 
 
401
    @ivar originalAttribute: name of the attribute of the proxy where the
 
402
        original object is stored.
 
403
    @type orginalAttribute: C{str}
 
404
    """
 
405
    def __init__(self, attributeName, originalAttribute):
 
406
        self.attributeName = attributeName
 
407
        self.originalAttribute = originalAttribute
 
408
 
 
409
 
 
410
    def __get__(self, oself, type=None):
 
411
        """
 
412
        Retrieve the C{self.attributeName} property from L{oself}.
 
413
        """
 
414
        if oself is None:
 
415
            return _ProxiedClassMethod(self.attributeName,
 
416
                                       self.originalAttribute)
 
417
        original = getattr(oself, self.originalAttribute)
 
418
        return getattr(original, self.attributeName)
 
419
 
 
420
 
 
421
    def __set__(self, oself, value):
 
422
        """
 
423
        Set the C{self.attributeName} property of L{oself}.
 
424
        """
 
425
        original = getattr(oself, self.originalAttribute)
 
426
        setattr(original, self.attributeName, value)
 
427
 
 
428
 
 
429
    def __delete__(self, oself):
 
430
        """
 
431
        Delete the C{self.attributeName} property of L{oself}.
 
432
        """
 
433
        original = getattr(oself, self.originalAttribute)
 
434
        delattr(original, self.attributeName)
 
435
 
 
436
 
 
437
 
 
438
__all__ = [
 
439
    # Sticking around:
 
440
    "ComponentsDeprecationWarning",
 
441
    "registerAdapter", "getAdapterFactory",
 
442
    "Adapter", "Componentized", "ReprableComponentized", "getRegistry",
 
443
    "proxyForInterface",
 
444
 
 
445
    # Deprecated:
 
446
    "backwardsCompatImplements",
 
447
    "fixClassImplements",
 
448
]