def test_proxyName(self): """ The name of a proxy class indicates which interface it proxies. """ proxy = proxyForInterface(IProxiedInterface) self.assertEqual(proxy.__name__, "(Proxy for seishub.core.tests." + \ "test_core_twisted_compatibility.IProxiedInterface)")
def test_original(self): """ Proxy objects should have an C{original} attribute which refers to the original object passed to the constructor. """ original = object() proxy = proxyForInterface(IProxiedInterface)(original) self.assertIdentical(proxy.original, original)
def test_multipleMethods(self): """ [Regression test] The proxy should send its method calls to the correct method, not the incorrect one. """ multi = MultipleMethodImplementor() proxy = proxyForInterface(IMultipleMethods)(multi) self.assertEquals(proxy.methodOne(), 1) self.assertEquals(proxy.methodTwo(), 2)
def test_proxyName(self): """ The name of a proxy class indicates which interface it proxies. """ proxy = proxyForInterface(IProxiedInterface) self.assertEquals( proxy.__name__, "(Proxy for " "twisted.python.test.test_components.IProxiedInterface)")
def test_proxyAttribute(self): """ Proxy objects should proxy declared attributes, but not other attributes. """ yayable = Yayable() yayable.ifaceAttribute = object() proxy = proxyForInterface(IProxiedInterface)(yayable) self.assertIdentical(proxy.ifaceAttribute, yayable.ifaceAttribute) self.assertRaises(AttributeError, lambda: proxy.yays)
def test_proxySetAttribute(self): """ The attributes that proxy objects proxy should be assignable and affect the original object. """ yayable = Yayable() proxy = proxyForInterface(IProxiedInterface)(yayable) thingy = object() proxy.ifaceAttribute = thingy self.assertIdentical(yayable.ifaceAttribute, thingy)
def test_proxyDeleteAttribute(self): """ The attributes that proxy objects proxy should be deletable and affect the original object. """ yayable = Yayable() yayable.ifaceAttribute = None proxy = proxyForInterface(IProxiedInterface)(yayable) del proxy.ifaceAttribute self.assertFalse(hasattr(yayable, 'ifaceAttribute'))
def test_proxyMethod(self): """ The class created from L{proxyForInterface} passes methods on an interface to the object which is passed to its constructor. """ klass = proxyForInterface(IProxiedInterface) yayable = Yayable() proxy = klass(yayable) proxy.yay() self.assertEquals(proxy.yay(), 2) self.assertEquals(yayable.yays, 2)
def repeat_call_proxy_for(interface, provider): """ Constructs an implementation of interface that calls the corresponding method on implementation twice for every call to a method. :interface param: The zope interface that the proxy should implement. :provider param: The underlying provider to proxy all method calls to. """ # proxyForInterface used so that only the methods of the interface are # exposed. The naive implementation of _RepeatProxy forwards all methods # rather than just the methods that are part of the interface. return proxyForInterface(interface, originalAttribute="_original")(_RepeatProxy(_provider=provider))
def test_interfaceInheritance(self): """ Proxies of subinterfaces generated with proxyForInterface should allow access to attributes of both the child and the base interfaces. """ proxyClass = proxyForInterface(IProxiedSubInterface) booable = Booable() proxy = proxyClass(booable) proxy.yay() proxy.boo() self.failUnless(booable.yayed) self.failUnless(booable.booed)
def loggedReactor(reactor): """ Construct and return a wrapper around the given C{reactor} which provides all of the same interfaces, but which will log all traffic over outgoing TCP connections it establishes. """ bases = [] for iface in providedBy(reactor): if iface is IReactorTCP: bases.append(_TCPTrafficLoggingReactor) else: bases.append(proxyForInterface(iface, '_reactor')) if bases: return type('(Logged Reactor)', tuple(bases), {})(reactor) return reactor
def test_decoratedProxyMethod(self): """ Methods of the class created from L{proxyForInterface} can be used with the decorator-helper L{functools.wraps}. """ base = proxyForInterface(IProxiedInterface) class klass(base): @wraps(base.yay) def yay(self): self.original.yays += 1 return base.yay(self) original = Yayable() yayable = klass(original) yayable.yay() self.assertEqual(2, original.yays)
def service(self, services=None): if services is None: services = (self.xmlService(),) # # Make sure aggregate DirectoryService isn't making # implementation assumptions about the IDirectoryService # objects it gets. # services = tuple(( proxyForInterface(IDirectoryService)(s) for s in services )) class TestService(DirectoryService, QueryMixIn): pass return TestService("xyzzy", services)
def test_attributeCustomization(self): """ The original attribute name can be customized via the C{originalAttribute} argument of L{proxyForInterface}: the attribute should change, but the methods of the original object should still be callable, and the attributes still accessible. """ yayable = Yayable() yayable.ifaceAttribute = object() proxy = proxyForInterface( IProxiedInterface, originalAttribute='foo')(yayable) self.assertIdentical(proxy.foo, yayable) # Check the behavior self.assertEquals(proxy.yay(), 1) self.assertIdentical(proxy.ifaceAttribute, yayable.ifaceAttribute) thingy = object() proxy.ifaceAttribute = thingy self.assertIdentical(yayable.ifaceAttribute, thingy) del proxy.ifaceAttribute self.assertFalse(hasattr(yayable, 'ifaceAttribute'))
class Thru(proxyForInterface(IDrain, "_outDrain")): r""" A fan.L{Thru} takes an input and fans it I{thru} multiple drains-which-produce-founts, such as L{tubes <tubes.itube.ITube>}:: Your Fount (producing "foo") | v Thru | _/|\_ _/ | \_ / | \ foo2bar foo2baz foo2qux \_ | _/ \_ | _/ \|/ | v Thru | v Your Drain (receiving a combination of foo, bar, baz) The way you would construct such a flow in code would be:: yourFount.flowTo(Thru([series(foo2bar()), series(foo2baz()), series(foo2qux())])).flowTo(yourDrain) """ def __init__(self, drains): """ Create a L{Thru} with an iterable of L{IDrain}. All of the drains in C{drains} should be drains that produce a new L{IFount} from L{flowingFrom <IDrain.flowingFrom>}, which means they should be a L{series <tubes.tube.series>} of L{tubes <tubes.itube.ITube>}, or drains that behave like that, such as L{Thru} itself. @param drain: an iterable of L{IDrain} """ self._in = In() self._out = Out() self._drains = list(drains) self._founts = list(None for drain in self._drains) self._outFounts = list(self._out.newFount() for drain in self._drains) self._inDrains = list(self._in.newDrain() for drain in self._drains) self._outDrain = self._out.drain def flowingFrom(self, fount): """ Accept input from C{fount} and produce output filtered by all of the C{drain}s given to this L{Thru}'s constructor. @param fount: a fount whose outputs should flow through our series of transformations. @return: an output fount which aggregates all the values produced by the drains given to this L{Thru}'s constructor. """ super(Thru, self).flowingFrom(fount) for idx, appDrain, outFount, inDrain in zip(count(), self._drains, self._outFounts, self._inDrains): appFount = outFount.flowTo(appDrain) if appFount is None: appFount = self._founts[idx] else: self._founts[idx] = appFount appFount.flowTo(inDrain) nextFount = self._in.fount # Literally copy/pasted from _SiphonDrain.flowingFrom. Hmm. nextDrain = nextFount.drain if nextDrain is None: return nextFount return nextFount.flowTo(nextDrain)
class ComparisonProxy(proxyForInterface(interface, "_original")): def __cmp__(self, other): return comparison_result
class DistReporter(proxyForInterface(IReporter)): """ See module docstring. """ def __init__(self, original): super(DistReporter, self).__init__(original) self.running = {} def startTest(self, test): """ Queue test starting. """ self.running[test.id()] = [] self.running[test.id()].append((self.original.startTest, test)) def addFailure(self, test, fail): """ Queue adding a failure. """ self.running[test.id()].append((self.original.addFailure, test, fail)) def addError(self, test, error): """ Queue error adding. """ self.running[test.id()].append((self.original.addError, test, error)) def addSkip(self, test, reason): """ Queue adding a skip. """ self.running[test.id()].append((self.original.addSkip, test, reason)) def addUnexpectedSuccess(self, test, todo): """ Queue adding an unexpected success. """ self.running[test.id()].append( (self.original.addUnexpectedSuccess, test, todo)) def addExpectedFailure(self, test, error, todo): """ Queue adding an unexpected failure. """ self.running[test.id()].append( (self.original.addExpectedFailure, test, error, todo)) def addSuccess(self, test): """ Queue adding a success. """ self.running[test.id()].append((self.original.addSuccess, test)) def stopTest(self, test): """ Queue stopping the test, then unroll the queue. """ self.running[test.id()].append((self.original.stopTest, test)) for step in self.running[test.id()]: apply(step[0], step[1:]) del self.running[test.id()]
def test_implements(self): """ The resulting proxy implements the interface that it proxies. """ proxy = proxyForInterface(IProxiedInterface) self.assertTrue(IProxiedInterface.implementedBy(proxy))
class TestResultDecorator( proxyForInterface(itrial.IReporter, "_originalReporter")): """
class YayableWrapper(proxyForInterface(IProxiedInterface)): """
class TestResultDecorator( proxyForInterface(itrial.IReporter, "_originalReporter") # type: ignore[misc] ): """
class _SchemaBuilderProxy(components.proxyForInterface(IAMQPSchemaBuilder)): pass
class HashedLeaseInfo(proxyForInterface(ILeaseInfo, "_lease_info") ): # type: ignore # unsupported dynamic base class """ A ``HashedLeaseInfo`` wraps lease information in which the secrets have been hashed. """ _lease_info = attr.ib() _hash = attr.ib() # proxyForInterface will take care of forwarding all methods on ILeaseInfo # to `_lease_info`. Here we override a few of those methods to adjust # their behavior to make them suitable for use with hashed secrets. def renew(self, new_expire_time): # Preserve the HashedLeaseInfo wrapper around the renewed LeaseInfo. return attr.assoc( self, _lease_info=super(HashedLeaseInfo, self).renew(new_expire_time), ) def is_renew_secret(self, candidate_secret): # type: (bytes) -> bool """ Hash the candidate secret and compare the result to the stored hashed secret. """ return super(HashedLeaseInfo, self).is_renew_secret(self._hash(candidate_secret)) def present_renew_secret(self): # type: () -> str """ Present the hash of the secret with a marker indicating it is a hash. """ return u"hash:" + super(HashedLeaseInfo, self).present_renew_secret() def is_cancel_secret(self, candidate_secret): # type: (bytes) -> bool """ Hash the candidate secret and compare the result to the stored hashed secret. """ if isinstance(candidate_secret, _HashedCancelSecret): # Someone read it off of this object in this project - probably # the lease crawler - and is just trying to use it to identify # which lease it wants to operate on. Avoid re-hashing the value. # # It is important that this codepath is only availably internally # for this process to talk to itself. If it were to be exposed to # clients over the network, they could just provide the hashed # value to avoid having to ever learn the original value. hashed_candidate = candidate_secret.hashed_value else: # It is not yet hashed so hash it. hashed_candidate = self._hash(candidate_secret) return super(HashedLeaseInfo, self).is_cancel_secret(hashed_candidate) def present_cancel_secret(self): # type: () -> str """ Present the hash of the secret with a marker indicating it is a hash. """ return u"hash:" + super(HashedLeaseInfo, self).present_cancel_secret() @property def owner_num(self): return self._lease_info.owner_num @property def nodeid(self): return self._lease_info.nodeid @property def cancel_secret(self): """ Give back an opaque wrapper around the hashed cancel secret which can later be presented for a succesful equality comparison. """ # We don't *have* the cancel secret. We hashed it and threw away the # original. That's good. It does mean that some code that runs # in-process with the storage service (LeaseCheckingCrawler) runs into # some difficulty. That code wants to cancel leases and does so using # the same interface that faces storage clients (or would face them, # if lease cancellation were exposed). # # Since it can't use the hashed secret to cancel a lease (that's the # point of the hashing) and we don't have the unhashed secret to give # it, instead we give it a marker that `cancel_lease` will recognize. # On recognizing it, if the hashed value given matches the hashed # value stored it is considered a match and the lease can be # cancelled. # # This isn't great. Maybe the internal and external consumers of # cancellation should use different interfaces. return _HashedCancelSecret(self._lease_info.cancel_secret)
def test_provides(self): """ The resulting proxy provides the Interface that it proxies. """ proxy = proxyForInterface(IProxiedInterface) self.assertTrue(IProxiedInterface.providedBy(proxy))