def __init__(self, clazz): self.clazz = clazz flattened = AttrDict() self.flattened = flattened assert clazz is not None resolved_mro = inspect.getmro(clazz) for parentclass in reversed(resolved_mro): flattened.update(parentclass.__dict__) self._proxy_for = (clazz, ) init = flattened['__init__'] if _get_method_regs(init): raise NotInstantiableError( "%r: cannot register class %r for instantiation with listening __init__" % (self, clazz)) self.method_regs = set() self.registered = False for name, attribute in flattened.items(): regs = _get_method_regs(attribute) if regs: for reg in regs: self.method_regs.add((name, reg)) self.instance_methods = {} self.instances = {}
def test_protocol(monkeypatch): conn_hooks = AttrDict() monkeypatch.setattr(hook, "connection", conn_hooks) delimiter_sentinel = object() server = AttrDict(delimiter=delimiter_sentinel) factory = main.ConnectionFactory(server) assert factory.server is server protocol = factory.buildProtocol("irc.example.net") assert server._reactor_connection is protocol assert protocol.server is server assert protocol.delimiter is server.delimiter conn_hooks.made = Hook() result = AttrDict() updated = Counter() @conn_hooks.made def onmade(event): result.update(event) updated.tick() protocol.connectionMade() assert updated.incremented(1) # goes out of its way to not assert that the connection # object is actually what is passed into the event call @result.conn.received def received(event): assert event.line == "incoming line" event.received = True event.command = "command" commands = Counter() @result.conn.received("command") def received_command(event): assert event.received == True commands.tick() protocol.lineReceived("incoming line") assert commands.incremented(1) disconnect_count = Counter() reason_sentinel = object() @result.conn.disconnect def disconnected(event): assert event.reason is reason_sentinel disconnect_count.tick() protocol.connectionLost(reason_sentinel) assert disconnect_count.incremented(1)
def test_mainloop(): counter = Counter() def run(): counter.tick() reactor = AttrDict(run=run) event = AttrDict(reactor=reactor) main.mainloop(event) assert counter.incremented(1)
def test_lazy_call(): lazycall = LazyCall(("herp", "derp"), ("args",), {"key": "words"}, False) counter = Counter() def target(value, key): assert value == "args" assert key == "words" counter.tick() herp = AttrDict(derp=target) obj = AttrDict(herp=herp) assert counter.incremented(0) lazycall.resolve(obj) assert counter.incremented(1)
def fire(self, *contexts, **keywords): try: if not self.mainloop: return except AttributeError: raise AlreadyRunningError() from crow2.util import AttrDict event = AttrDict() for context in contexts + (keywords,): event.update(context) mainloop = self.mainloop # if a plugin tries to start the mainloop again, it should fail del self.mainloop mainloop(event) self.mainloop = mainloop
def test_errors(self, capsys): class Clazz(object): def __init__(self, event): pass def delete(self): should_never_run() reg = _HandlerClass(Clazz) event = AttrDict() instance2 = Clazz(event) with pytest.raises(exceptions.NotRegisteredError): reg.free_instance(instance2) out, err = capsys.readouterr() reg(event) out, err = capsys.readouterr() assert "WARNING" in out or "WARNING" in err class OtherClazz(object): def __init__(self, event): should_never_run() __init__._crow2_instancehookregs = [DummyAttributeRegistration()] with pytest.raises(exceptions.NotInstantiableError): otherreg = _HandlerClass(OtherClazz)
def test_lazy_missing(): lazycall = LazyCall(("doesnt", "exist", "attribute"), ("argument",), {"key": "value"}, False) exist = AttrDict() doesnt = AttrDict(exist=exist) obj = AttrDict(doesnt=doesnt) try: lazycall.resolve(obj) except AttributeError as e: assert "doesnt.exist" in e.message assert "attribute" in e.message assert "key" in e.message assert "value" in e.message assert "argument" in e.message assert repr(obj) in e.message else: should_never_run()
def _make_eventobj(self, *dicts, **keywords): """ Prepare the objects which will be passed into handlers """ event = AttrDict() for context_dict in dicts: event.update(context_dict) event.update(keywords) event.update({"calling_hook": self}) return event
def to_attrdict(obj, recurse=True): # todo: this should probably be interface-based since it does type checking if isinstance(obj, dict): obj = AttrDict(obj) if recurse: for key in obj: res = to_attrdict(obj[key]) obj[key] = res return obj
def test_server_connect(monkeypatch): connections = [] def fakeconnecttcp(address, port, factory): connections.append((address, port, factory)) reactor = AttrDict(connectTCP=fakeconnecttcp) options = AttrDict({ "server": object(), "port": object(), "nick": object(), "user": object(), "realname": object(), "channels": object(), "newline": object() }) fakeconnectionfactories = [] class FakeConnectionFactory(object): def __init__(self, serverobj): self.serverobj = serverobj fakeconnectionfactories.append(self) monkeypatch.setattr(main, "ConnectionFactory", FakeConnectionFactory) server = main.Server(reactor, "connection_name", options) assert server.address is options.server assert server.port is options.port assert server.nick is options.nick assert server.user is options.user assert server.realname is options.realname assert server.channels is options.channels assert server.delimiter is options.newline assert server.factory.serverobj is server # yay reference loop! assert not len(connections) server.connect() assert connections == [(options.server, options.port, fakeconnectionfactories[0])]
def test_init_unconfigured(monkeypatch): monkeypatch.setattr(main, "log", AttrDict(startLogging=lambda out, setStdout: None)) class FakeServer(object): def __init__(self, reactor, name, options): should_never_run() def connect(self): should_never_run() monkeypatch.setattr(main, "Server", FakeServer) reactor_sentinel = object() event = AttrDict(config=AttrDict()) main.defaultconfig(event) with pytest.raises(main.UnconfiguredError): main.init(event)
def test_defaultconfig(monkeypatch): event = AttrDict(config=AttrDict()) assert event == {"config": {}} main.defaultconfig(event) assert event == { "config": { "connections": { "example": { "server": "irc.example.net", "nick": "example", "user": "******", "realname": "example", "channels": ["#changeme"] } } } }
def test_init(monkeypatch): startLogging_counter = Counter() def startLogging(outfile, setStdout=True): assert setStdout == False assert outfile is sys.stdout startLogging_counter.tick() logstub = AttrDict(startLogging=startLogging) fakeservers = {} class FakeServer(object): def __init__(self, reactor, name, options): self.reactor = reactor self.name = name self.options = options self.connected = False fakeservers[name] = self def connect(self): self.connected = True monkeypatch.setattr(main, "log", logstub) monkeypatch.setattr(main, "Server", FakeServer) reactor_sentinel = object() connections = {"test_1": object(), "test_2": object()} config = AttrDict(connections=connections) event = AttrDict(config=config, reactor=reactor_sentinel) main.init(event) assert startLogging_counter.incremented(1) assert len(fakeservers) == len(connections) assert all(fakeserver.reactor is reactor_sentinel for fakeserver in fakeservers.values()) assert all(fakeserver.connected for fakeserver in fakeservers.values()) assert fakeservers["test_1"].options is connections["test_1"] assert fakeservers["test_2"].options is connections["test_2"]
def test_exception_in_call(): lazycall = LazyCall(("herp", "derp"), ("positional_arg",), {"keyword": "kwarg"}, False) class SentinelException(Exception): pass def target(positional_arg, keyword): assert positional_arg == "positional_arg" assert keyword == "kwarg" raise SentinelException() herp = AttrDict(derp=target) obj = AttrDict(herp=herp) try: lazycall.resolve(obj) except exceptions.ExceptionInCallError as e: assert "SentinelException" in e.message assert "target" in e.message assert "herp.derp" in e.message else: should_never_run()
def test_lazy_decorate(): lazycall = LazyCall(("decorator",), (), {}, True, True) decorate_count = Counter() def sentinel_func(): should_never_run() def simple_decorator(func): assert func is sentinel_func decorate_count.tick() obj = AttrDict(decorator=simple_decorator) lazycall.resolve(obj, sentinel_func) assert decorate_count.incremented(1)
def test_class_reg(): registrations = [] def register(handler, *args, **keywords): registrations.append((handler, args, keywords)) hook = AttrDict(register=register) @handlerclass(hook) @handlerclass(hook, "derp") @handlerclass(hook, derp=True) class Target(object): pass assert registrations == [(Target._crow2_classreg, (), {"derp": True}), (Target._crow2_classreg, ("derp",), {}), (Target._crow2_classreg, (), {})]
def test_deferred_adaptation(): hook1 = Hook() @hook1 @yielding def handler(event): event.handler_called = True deferred_result = yield event.deferred deferred_result.handler_called = True event = hook1.fire(deferred=Deferred()) newevent = AttrDict() event.deferred.callback(newevent) assert newevent.handler_called
def test_instancehandler_missinghook(): class MissingHook(object): @instancehandler.doesnt.exist def a_method(self, event): should_never_run() target = MissingHook() a_method = target.a_method.im_func regs = a_method._crow2_instancehookregs reg = regs[0] event = AttrDict() with pytest.raises(AttributeError): reg.add_bound_method(target.a_method, event)
def config(event): print "loading config" config_type = "json" filename = "config." + config_type config = AttrDict() load_event = loadhook.fire(event, config_type=config_type, filename=filename, config=config) config = to_attrdict(load_event.config) write_event = writehook.fire(event, config_type=config_type, filename=filename, config=config) config = to_attrdict(write_event.config) event.main.config = config event.config = config
def test_instancehandler_badarguments(): class BadArguments(object): @instancehandler.func(doesnt="take", arguments=True) def a_method(self, event): should_never_run() target = BadArguments() a_method = target.a_method.im_func regs = a_method._crow2_instancehookregs reg = regs[0] def func(): """ A function that takes no arguments """ should_never_run() event = AttrDict(func=func) with pytest.raises(exceptions.ExceptionInCallError): reg.add_bound_method(target.a_method, event)
def test_simple(self): class Clazz(object): def __init__(self, event): pass def herp(self): should_never_run() herp._crow2_instancehookregs = [DummyAttributeRegistration()] def derp(self): self.delete() herp = vars(Clazz)["herp"] dummy = herp._crow2_instancehookregs[0] reg = _HandlerClass(Clazz) assert len(dummy.registereds) == 0 assert len(dummy.bounds) == 0 event = AttrDict() instance = reg(event) assert dummy.registereds == [(Clazz, "herp")] assert dummy.bounds == [(instance.herp, event)] instance.derp() assert dummy.unbounds == [instance.herp] assert dummy.unregistereds == [(Clazz, "herp")]
def test_server_defaults(monkeypatch): options = AttrDict({ "server": object(), "nick": object(), "channels": object() }) reactor_sentinel = object() monkeypatch.setattr(main, "ConnectionFactory", lambda server: None) server = main.Server(reactor_sentinel, "connection_name", options) assert server.name == "connection_name" assert server.port == 6667 assert server.address is options.server assert server.nick is options.nick assert server.channels is options.channels assert server.user is options.nick assert server.realname is options.nick assert server.delimiter == "\r\n" assert server.reactor is reactor_sentinel
def test_lazy_decorate_missing(): lazycall = LazyCall((), (), {}, True, True) with pytest.raises(exceptions.DecoratedFuncMissingError): lazycall.resolve(AttrDict(), None)
def test_instancehandler(): class Target(object): def __init__(self): self.counter = Counter() @instancehandler.thing.hook @instancehandler.otherthing.otherhook() @instancehandler.argthing.arg(derp=True) def a_method(self, event): should_never_run() a_method = vars(Target)["a_method"] regs = a_method._crow2_instancehookregs by_names = dict([(reg.attributes, reg) for reg in regs]) assert set(by_names.keys()) == set((("thing", "hook"), ("otherthing", "otherhook"), ("argthing", "arg"))) instances = [Target(), Target()] unregister_counter = Counter() for instance in instances: simple_counter = Counter() partial_counter = Counter() arg_counter = Counter() def simpledecorator(func): simple_counter.tick() def partialdecorator(): partial_counter.tick() def partial(func): partial_counter.tick() return partial def argdecorator(derp): arg_counter.tick() def partial(func): arg_counter.tick() return partial argdecorator.unregister = lambda func: unregister_counter.tick() partialdecorator.unregister = lambda func: unregister_counter.tick() simpledecorator.unregister = lambda func: unregister_counter.tick() event = AttrDict() event.thing = AttrDict(hook=simpledecorator) event.otherthing = AttrDict(otherhook=partialdecorator) event.argthing = AttrDict(arg=argdecorator) by_names["thing", "hook"].add_bound_method(instance.a_method, event) assert simple_counter.incremented(1) by_names["otherthing", "otherhook"].add_bound_method(instance.a_method, event) assert partial_counter.incremented(2) by_names["argthing", "arg"].add_bound_method(instance.a_method, event) assert arg_counter.incremented(2) for instance in instances: by_names["thing", "hook"].remove_bound_method(instance.a_method) by_names["otherthing", "otherhook"].remove_bound_method(instance.a_method) by_names["argthing", "arg"].remove_bound_method(instance.a_method) assert unregister_counter.incremented(3)
def test_loadreactor(monkeypatch): from twisted.internet import reactor event = AttrDict() main.loadreactor(event) assert event == {"reactor": reactor}