async def accepts_type_definition_with_async_subscribe_function(): pubsub = EventEmitter() async def subscribe_email(_inbox, _info): return EventEmitterAsyncIterator(pubsub, "importantEmail") schema = GraphQLSchema( query=QueryType, subscription=GraphQLObjectType( "Subscription", { "importantEmail": GraphQLField(GraphQLString, subscribe=subscribe_email) }, ), ) ast = parse(""" subscription { importantEmail } """) subscription = await subscribe(schema, ast) pubsub.emit("importantEmail", {"importantEmail": {}}) await anext(subscription)
async def aclose_cleans_up(): emitter = EventEmitter() assert emitter.listeners["publish"] == [] iterator = EventEmitterAsyncIterator(emitter, "publish") assert emitter.listeners["publish"] == [iterator.queue.put] assert not iterator.closed for value in range(3): emitter.emit("publish", value) await sleep(0) assert iterator.queue.qsize() == 3 await iterator.aclose() assert emitter.listeners["publish"] == [] assert iterator.queue.empty() assert iterator.closed
async def produces_a_payload_for_multiple_subscribe_in_same_subscription(): pubsub = EventEmitter() send_important_email, subscription = await create_subscription(pubsub) second = await create_subscription(pubsub) payload1 = anext(subscription) payload2 = anext(second[1]) assert (send_important_email({ "from": "*****@*****.**", "subject": "Alright", "message": "Tests are good", "unread": True, }) is True) expected_payload = { "importantEmail": { "email": { "from": "*****@*****.**", "subject": "Alright" }, "inbox": { "unread": 1, "total": 2 }, } } assert await payload1 == (expected_payload, None) assert await payload2 == (expected_payload, None)
async def accepts_multiple_subscription_fields_defined_in_schema(): pubsub = EventEmitter() SubscriptionTypeMultiple = GraphQLObjectType( "Subscription", { "importantEmail": GraphQLField(EmailEventType), "nonImportantEmail": GraphQLField(EmailEventType), }, ) test_schema = GraphQLSchema( query=QueryType, subscription=SubscriptionTypeMultiple ) send_important_email, subscription = await create_subscription( pubsub, test_schema ) send_important_email( { "from": "*****@*****.**", "subject": "Alright", "message": "Tests are good", "unread": True, } ) await anext(subscription)
async def produces_a_payload_for_multiple_subscribe_in_same_subscription(): pubsub = EventEmitter() send_important_email, subscription = await create_subscription(pubsub) second = await create_subscription(pubsub) payload1 = anext(subscription) payload2 = anext(second[1]) assert send_important_email({ 'from': '*****@*****.**', 'subject': 'Alright', 'message': 'Tests are good', 'unread': True }) is True expected_payload = { 'importantEmail': { 'email': { 'from': '*****@*****.**', 'subject': 'Alright' }, 'inbox': { 'unread': 1, 'total': 2 }, } } assert await payload1 == (expected_payload, None) assert await payload2 == (expected_payload, None)
async def event_order_is_correct_for_multiple_publishes(): pubsub = EventEmitter() send_important_email, subscription = await create_subscription(pubsub) payload = anext(subscription) # A new email arrives! assert (send_important_email({ "from": "*****@*****.**", "subject": "Message", "message": "Tests are good", "unread": True, }) is True) # A new email arrives! assert (send_important_email({ "from": "*****@*****.**", "subject": "Message 2", "message": "Tests are good 2", "unread": True, }) is True) assert await payload == ( { "importantEmail": { "email": { "from": "*****@*****.**", "subject": "Message" }, "inbox": { "unread": 2, "total": 3 }, } }, None, ) payload = subscription.__anext__() assert await payload == ( { "importantEmail": { "email": { "from": "*****@*****.**", "subject": "Message 2" }, "inbox": { "unread": 2, "total": 3 }, } }, None, )
async def produces_a_payload_when_there_are_multiple_events(): pubsub = EventEmitter() send_important_email, subscription = await create_subscription(pubsub) payload = anext(subscription) # A new email arrives! assert (send_important_email({ "from": "*****@*****.**", "subject": "Alright", "message": "Tests are good", "unread": True, }) is True) assert await payload == ( { "importantEmail": { "email": { "from": "*****@*****.**", "subject": "Alright" }, "inbox": { "unread": 1, "total": 2 }, } }, None, ) payload = anext(subscription) # A new email arrives! assert (send_important_email({ "from": "*****@*****.**", "subject": "Alright 2", "message": "Tests are good 2", "unread": True, }) is True) assert await payload == ( { "importantEmail": { "email": { "from": "*****@*****.**", "subject": "Alright 2" }, "inbox": { "unread": 2, "total": 3 }, } }, None, )
async def resolves_to_an_error_if_variables_were_wrong_type(): # If we receive variables that cannot be coerced correctly, subscribe() # will resolve to an ExecutionResult that contains an informative error # description. ast = parse( """ subscription ($priority: Int) { importantEmail(priority: $priority) { email { from subject } inbox { unread total } } } """ ) pubsub = EventEmitter() data = { "inbox": { "emails": [ { "from": "*****@*****.**", "subject": "Hello", "message": "Hello World", "unread": False, } ] }, "importantEmail": lambda _info: EventEmitterAsyncIterator( pubsub, "importantEmail" ), } result = await subscribe( email_schema, ast, data, variable_values={"priority": "meow"} ) assert result == ( None, [ { "message": "Variable '$priority' got invalid value 'meow'; Expected" " type Int; Int cannot represent non-integer value: 'meow'", "locations": [(2, 27)], } ], ) assert result.errors[0].original_error is not None
async def should_not_trigger_when_subscription_is_thrown(): pubsub = EventEmitter() send_important_email, subscription = await create_subscription(pubsub) payload = anext(subscription) # A new email arrives! assert ( send_important_email( { "from": "*****@*****.**", "subject": "Alright", "message": "Tests are good", "unread": True, } ) is True ) assert await payload == ( { "importantEmail": { "email": {"from": "*****@*****.**", "subject": "Alright"}, "inbox": {"unread": 1, "total": 2}, } }, None, ) payload = anext(subscription) # Throw error with raises(RuntimeError) as exc_info: await subscription.athrow(RuntimeError("ouch")) assert str(exc_info.value) == "ouch" # A new email arrives! assert ( send_important_email( { "from": "*****@*****.**", "subject": "Alright 2", "message": "Tests are good 2", "unread": True, } ) is False ) with raises(StopAsyncIteration): await payload
async def event_order_is_correct_for_multiple_publishes(): pubsub = EventEmitter() send_important_email, subscription = await create_subscription(pubsub) payload = anext(subscription) # A new email arrives! assert send_important_email({ 'from': '*****@*****.**', 'subject': 'Message', 'message': 'Tests are good', 'unread': True }) is True # A new email arrives! assert send_important_email({ 'from': '*****@*****.**', 'subject': 'Message 2', 'message': 'Tests are good 2', 'unread': True }) is True assert await payload == ({ 'importantEmail': { 'email': { 'from': '*****@*****.**', 'subject': 'Message' }, 'inbox': { 'unread': 2, 'total': 3 }, } }, None) payload = subscription.__anext__() assert await payload == ({ 'importantEmail': { 'email': { 'from': '*****@*****.**', 'subject': 'Message 2' }, 'inbox': { 'unread': 2, 'total': 3 }, } }, None)
async def resolves_to_an_error_for_unknown_subscription_field(): ast = parse(""" subscription { unknownField } """) pubsub = EventEmitter() subscription = (await create_subscription(pubsub, ast=ast))[1] assert subscription == (None, [{ 'message': "The subscription field 'unknownField' is not defined.", 'locations': [(3, 15)] }])
async def should_not_trigger_when_subscription_is_already_done(): pubsub = EventEmitter() send_important_email, subscription = await create_subscription(pubsub) payload = anext(subscription) # A new email arrives! assert ( send_important_email( { "from": "*****@*****.**", "subject": "Alright", "message": "Tests are good", "unread": True, } ) is True ) assert await payload == ( { "importantEmail": { "email": {"from": "*****@*****.**", "subject": "Alright"}, "inbox": {"unread": 1, "total": 2}, } }, None, ) payload = anext(subscription) await subscription.aclose() # A new email arrives! assert ( send_important_email( { "from": "*****@*****.**", "subject": "Alright 2", "message": "Tests are good 2", "unread": True, } ) is False ) with raises(StopAsyncIteration): await payload
async def resolves_to_an_error_if_variables_were_wrong_type(): # If we receive variables that cannot be coerced correctly, subscribe() # will resolve to an ExecutionResult that contains an informative error # description. ast = parse(""" subscription ($priority: Int) { importantEmail(priority: $priority) { email { from subject } inbox { unread total } } } """) pubsub = EventEmitter() data = { 'inbox': { 'emails': [{ 'from': '*****@*****.**', 'subject': 'Hello', 'message': 'Hello World', 'unread': False }] }, 'importantEmail': lambda _info: EventEmitterAsyncIterator(pubsub, 'importantEmail') } result = await subscribe(email_schema, ast, data, variable_values={'priority': 'meow'}) assert result == (None, [{ 'message': "Variable '$priority' got invalid value 'meow'; Expected" " type Int; Int cannot represent non-integer value: 'meow'", 'locations': [(2, 27)] }]) assert result.errors[0].original_error is not None
async def throws_an_error_if_subscribe_does_not_return_an_iterator(): invalid_email_schema = GraphQLSchema( query=QueryType, subscription=GraphQLObjectType( 'Subscription', { 'importantEmail': GraphQLField(GraphQLString, subscribe=lambda _inbox, _info: 'test') })) pubsub = EventEmitter() with raises(TypeError) as exc_info: await create_subscription(pubsub, invalid_email_schema) assert str(exc_info.value) == ( "Subscription field must return AsyncIterable. Received: 'test'")
async def startup(app): authentication = AuthenticationMiddleware( whitelist=['__schema', 'registerUser', 'authenticate']) db = app['mongo'] config = app['config'] event_emitter = EventEmitter() repositories = edict(admin=AdminRepository(), user=UserRepository(), blog=BlogRepository(), post=PostRepository(), comment=CommentRepository()) data_loader_registry = DbDataLoaderRegistry() for repository in repositories.values(): repository.register_data_loaders(data_loader_registry) context_builder = lambda request: edict(config=config, db=db, event_emitter=event_emitter, repositories=repositories, data_loaders=data_loader_registry. create_loders(db), request=request) middleware = [authentication] controller = GraphQLController(schema, context_builder, middleware) routes = controller.add_routes(app) app['graphql'] = controller # Configure default CORS settings. cors = aiohttp_cors.setup(app, defaults={ "*": aiohttp_cors.ResourceOptions( allow_credentials=True, expose_headers="*", allow_headers="*", ) }) for route in routes: cors.add(route)
async def emit_async(): emitter = EventEmitter() emitted = [] async def listener(value): emitted.append(value) emitter.add_listener("foo", listener) emitter.emit("foo", "bar") emitter.emit("bar", "baz") await sleep(0) assert emitted == ["bar"]
async def emit_async(): emitter = EventEmitter() emitted = [] async def listener(value): emitted.append(value) emitter.add_listener('foo', listener) emitter.emit('foo', 'bar') emitter.emit('bar', 'baz') await sleep(0) assert emitted == ['bar']
def emit_sync(): emitter = EventEmitter() emitted = [] def listener(value): emitted.append(value) emitter.add_listener("foo", listener) assert emitter.emit("foo", "bar") is True assert emitted == ["bar"] assert emitter.emit("bar", "baz") is False assert emitted == ["bar"]
def emit_sync(): emitter = EventEmitter() emitted = [] def listener(value): emitted.append(value) emitter.add_listener('foo', listener) assert emitter.emit('foo', 'bar') is True assert emitted == ['bar'] assert emitter.emit('bar', 'baz') is False assert emitted == ['bar']
async def subscribe_async_iterator_mock(): # Create an AsyncIterator from an EventEmitter emitter = EventEmitter() iterator = EventEmitterAsyncIterator(emitter, "publish") # Make sure it works as an async iterator assert iterator.__aiter__() is iterator assert callable(iterator.__anext__) # Queue up publishes assert emitter.emit("publish", "Apple") is True assert emitter.emit("publish", "Banana") is True # Read payloads assert await iterator.__anext__() == "Apple" assert await iterator.__anext__() == "Banana" # Read ahead i3 = iterator.__anext__() i4 = iterator.__anext__() # Publish assert emitter.emit("publish", "Coconut") is True assert emitter.emit("publish", "Durian") is True # Await results assert await i3 == "Coconut" assert await i4 == "Durian" # Read ahead i5 = iterator.__anext__() # Terminate emitter await iterator.aclose() # Publish is not caught after terminate assert emitter.emit("publish", "Fig") is False # Find that cancelled read-ahead got a "done" result with raises(StopAsyncIteration): await i5 # And next returns empty completion value with raises(StopAsyncIteration): await iterator.__anext__()
async def accepts_multiple_subscription_fields_defined_in_schema(): pubsub = EventEmitter() SubscriptionTypeMultiple = GraphQLObjectType( 'Subscription', { 'importantEmail': GraphQLField(EmailEventType), 'nonImportantEmail': GraphQLField(EmailEventType) }) test_schema = GraphQLSchema(query=QueryType, subscription=SubscriptionTypeMultiple) send_important_email, subscription = await create_subscription( pubsub, test_schema) send_important_email({ 'from': '*****@*****.**', 'subject': 'Alright', 'message': 'Tests are good', 'unread': True }) await anext(subscription)
async def subscribe_async_iterator_mock(): # Create an AsyncIterator from an EventEmitter emitter = EventEmitter() iterator = EventEmitterAsyncIterator(emitter, 'publish') # Queue up publishes assert emitter.emit('publish', 'Apple') is True assert emitter.emit('publish', 'Banana') is True # Read payloads assert await iterator.__anext__() == 'Apple' assert await iterator.__anext__() == 'Banana' # Read ahead i3 = iterator.__anext__() i4 = iterator.__anext__() # Publish assert emitter.emit('publish', 'Coconut') is True assert emitter.emit('publish', 'Durian') is True # Await results assert await i3 == 'Coconut' assert await i4 == 'Durian' # Read ahead i5 = iterator.__anext__() # Terminate emitter await iterator.aclose() # Publish is not caught after terminate assert emitter.emit('publish', 'Fig') is False # Find that cancelled read-ahead got a "done" result with raises(StopAsyncIteration): await i5 # And next returns empty completion value with raises(StopAsyncIteration): await iterator.__anext__()
def add_and_remove_listeners(): emitter = EventEmitter() def listener1(value): pass def listener2(value): pass emitter.add_listener("foo", listener1) emitter.add_listener("foo", listener2) emitter.add_listener("bar", listener1) assert emitter.listeners["foo"] == [listener1, listener2] assert emitter.listeners["bar"] == [listener1] emitter.remove_listener("foo", listener1) assert emitter.listeners["foo"] == [listener2] assert emitter.listeners["bar"] == [listener1] emitter.remove_listener("foo", listener2) assert emitter.listeners["foo"] == [] assert emitter.listeners["bar"] == [listener1] emitter.remove_listener("bar", listener1) assert emitter.listeners["bar"] == []
def emitter(self) -> EventEmitter: if not self._emitter: self._emitter = self._emitter = EventEmitter(self._loop) return self._emitter
async def produces_a_payload_per_subscription_event(): pubsub = EventEmitter() send_important_email, subscription = await create_subscription(pubsub) # Wait for the next subscription payload. payload = anext(subscription) # A new email arrives! assert (send_important_email({ "from": "*****@*****.**", "subject": "Alright", "message": "Tests are good", "unread": True, }) is True) # The previously waited on payload now has a value. assert await payload == ( { "importantEmail": { "email": { "from": "*****@*****.**", "subject": "Alright" }, "inbox": { "unread": 1, "total": 2 }, } }, None, ) # Another new email arrives, before subscription.___anext__ is called. assert (send_important_email({ "from": "*****@*****.**", "subject": "Tools", "message": "I <3 making things", "unread": True, }) is True) # The next waited on payload will have a value. assert await anext(subscription) == ( { "importantEmail": { "email": { "from": "*****@*****.**", "subject": "Tools" }, "inbox": { "unread": 2, "total": 3 }, } }, None, ) # The client decides to disconnect. # noinspection PyUnresolvedReferences await subscription.aclose() # Which may result in disconnecting upstream services as well. assert (send_important_email({ "from": "*****@*****.**", "subject": "Important", "message": "Read me please", "unread": True, }) is False) # No more listeners. # Awaiting subscription after closing it results in completed results. with raises(StopAsyncIteration): assert await anext(subscription)
def subscribe_non_important(_inbox, _info): did_resolve["nonImportantEmail"] = True return EventEmitterAsyncIterator(EventEmitter(), "event")
def __init__(self): self.emitter = EventEmitter() self.queue = EventEmitterAsyncIterator(self.emitter, "library")
def add_and_remove_listeners(): emitter = EventEmitter() def listener1(value): pass def listener2(value): pass emitter.add_listener('foo', listener1) emitter.add_listener('foo', listener2) emitter.add_listener('bar', listener1) assert emitter.listeners['foo'] == [listener1, listener2] assert emitter.listeners['bar'] == [listener1] emitter.remove_listener('foo', listener1) assert emitter.listeners['foo'] == [listener2] assert emitter.listeners['bar'] == [listener1] emitter.remove_listener('foo', listener2) assert emitter.listeners['foo'] == [] assert emitter.listeners['bar'] == [listener1] emitter.remove_listener('bar', listener1) assert emitter.listeners['bar'] == []
def __init__(self, **users): self._registry: Dict[str, User] = users self._emitter = EventEmitter()
notes: [Note!]! notesContaining(query: String!): [Note!]! } type Mutation { createNote(title: String!, body: String!): Note! sendMessage(message: String!): Boolean! } type Subscription { messages: String! } """ ) mutation = ResolverMap("Mutation") pubsub = EventEmitter() query = ResolverMap("Query") subscription = SubscriptionAwareResolverMap("Subscription") @query.field("hello") async def say_hello(root, info): await asyncio.sleep(3) return "Hello!" @query.field("notes") async def get_all_notes(root, info): await init_database() # FIXME: channels needs to expose the ready_callable from daphne notes = await Note.query.gino.all() return notes