PK!yEggcarly/__init__.pyfrom __future__ import print_function from .hook import hook, hookMethod from .context import Context PK!H carly/context.pyfrom functools import partial from collections import namedtuple from twisted.internet import reactor from twisted.internet.defer import inlineCallbacks, gatherResults, maybeDeferred from twisted.internet.protocol import Factory, ClientFactory from .hook import hook from .timeout import resolveTimeout TCPServer = namedtuple('TCPServer', ['protocolClass', 'port']) TCPClient = namedtuple('TCPClient', ['protocolClass', 'connection', 'protocol']) class Context(object): def __init__(self): self.cleanups = { 'connections': [], 'listens': [], } def _cleanup(self, cleanups, timeout): deferreds = [] for p in cleanups: d = p() deferreds.append(d) d.addTimeout(timeout, reactor) return gatherResults(deferreds) @inlineCallbacks def cleanup(self, timeout=None): timeout = resolveTimeout(timeout) yield self._cleanup(self.cleanups['connections'], timeout) yield self._cleanup(self.cleanups['listens'], timeout) def makeTCPServer(self, protocol, factory=None): protocolClass = hook(protocol, 'connectionLost') if factory is None: factory = Factory() factory.protocol = protocolClass port = reactor.listenTCP(0, factory) server = TCPServer(protocolClass, port) self.cleanupTCPServer(server) return server def cleanupTCPServer(self, server, timeout=None): timeout = resolveTimeout(timeout) self.cleanups['connections'].append( partial(server.protocolClass.connectionLost.called, timeout=timeout) ) self.cleanups['listens'].append( partial(maybeDeferred, server.port.stopListening) ) def makeTCPClient(self, protocol, port, factory=None): protocolClass = hook(protocol, 'connectionMade', 'connectionLost') if factory is None: factory = ClientFactory() factory.protocol = protocolClass connection = reactor.connectTCP('localhost', port.getHost().port, factory) client = TCPClient( protocolClass, connection, protocolClass.connectionMade.protocol() ) self.cleanupTCPClient(client) return client def cleanupTCPClient(self, client, timeout=None): timeout = resolveTimeout(timeout) self.cleanups['connections'].extend(( partial(maybeDeferred, client.connection.disconnect), partial(client.protocolClass.connectionLost.called, timeout=timeout), )) PK!υ^ ^ carly/hook.pyfrom __future__ import print_function from functools import partial from collections import namedtuple from twisted.internet.defer import Deferred from twisted.internet import reactor from types import ClassType from .timeout import resolveTimeout Result = namedtuple('Result', ['protocol', 'args', 'kw']) class BoundHook(object): def __init__(self, hooked, original, instance): self.hooked = hooked self.original = original self.instance = instance def __call__(self, *args, **kw): result = self.original(self.instance, *args, **kw) self.hooked._called.callback(Result(self.instance, args, kw)) return result def __getattr__(self, item): return getattr(self.hooked, item) class Call(object): def __init__(self, *args, **kw): self.args = args self.kw = kw class HookedCall(object): def __init__(self, class_, hook, decoder=Call): self._called = Deferred() self.original = getattr(class_, hook) self.decode = decoder def __get__(self, instance, owner): if instance is None: return self return BoundHook(self, self.original, instance) def _reset(self, handler, timeout, result): if isinstance(result, Result): return handler(result) else: self._called = Deferred() self._called.addTimeout(timeout, reactor).addCallback(handler) return self._called def _expectCallback(self, handler, timeout): timeout = resolveTimeout(timeout) return self._called.addTimeout(timeout, reactor).addCallback( partial(self._reset, handler, timeout) ) def called(self, decode=None, timeout=None): return self._expectCallback( lambda result: (decode or self.decode)(*result.args, **result.kw), timeout, ) def protocol(self, timeout=None): return self._expectCallback(lambda result: result.protocol, timeout) def hook(class_, *names): methods = {'__carly_hooked__': True} for name in names: d = Deferred() methods[name] = HookedCall(class_, name) if issubclass(class_, object): type_ = type else: # pragma: no cover # some protocols don't have object has a base class! type_ = ClassType return type_('Hooked'+class_.__name__, (class_,), methods) def hookMethod(class_, name, decoder=Call): if not getattr(class_, '__carly_hooked__', False): raise AssertionError("Can't hook a method on an unhooked class") setattr(class_, name, HookedCall(class_, name, decoder)) PK!6carly/timeout.pyDEFAULT_TIMEOUT = 0.2 def resolveTimeout(specified): if specified is None: return DEFAULT_TIMEOUT return specified PK!HqfWXcarly-0.2.0.dist-info/WHEEL A н#f."jm)!fb҅~ܴA,mTD}E n0H饹*|D[¬c i=0(q3PK!H=>carly-0.2.0.dist-info/METADATARN1+R|  .$@e o;(ٵ=&gQu'r0dWڡB=3Б=9CD6P1_tگ k8"arܛq y'1]ìJ >|lLK1Xh&m}ic7y$q)FV`6b êbڥ^̙J5'ڗuS-_[*Mkmk]kE_wm84uc^ٹ?PK!H9Tcarly-0.2.0.dist-info/RECORDur0@}%$.(+n2^w掝q~ӣM(!f'tq4U/f2Ǫ = qĮ(J7:~;ʼnJ+whO\2ޠSXjwKsGYNȥ2xfu|DMf|r…" RsJ-._yvāWDftp}c Sd2bo_q},9PZOZzydۿ88?($ 7׷Gt_sY[lO&5TC2m5M!PK!yEggcarly/__init__.pyPK!H carly/context.pyPK!υ^ ^ carly/hook.pyPK!6Ycarly/timeout.pyPK!HqfWX carly-0.2.0.dist-info/WHEELPK!H=>carly-0.2.0.dist-info/METADATAPK!H9Tcarly-0.2.0.dist-info/RECORDPK