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