def cancel_all(self, loop=None): if loop is None: loop = asyncio.get_event_loop() popitem_iter = iter_except(self.sessions.popitem, KeyError) stop_tasks = (maybe_awaitable(inst.stop) for _, inst in popitem_iter) loop.create_task(asyncio.gather(*stop_tasks))
def test_multiple(self): """ensure can catch multiple exceptions""" class Fiz(Exception): pass class Buzz(Exception): pass i = 0 def fizbuzz(): nonlocal i i += 1 if i % 3 == 0: raise Fiz if i % 5 == 0: raise Buzz return i expected = ([1, 2], [4], [], [7, 8], []) for x in expected: self.assertEqual(list(mi.iter_except(fizbuzz, (Fiz, Buzz))), x)
def test_first(self): """ensure first is run before the function""" l = [1, 2, 3] f = lambda: 25 i = mi.iter_except(l.pop, IndexError, f) self.assertEqual(list(i), [25, 3, 2, 1])
def test_uncaught_exception_is_raised(self): """ensure a non-specified exception is raised""" l = [1, 2, 3] i = mi.iter_except(l.pop, KeyError) self.assertRaises(IndexError, lambda: list(i))
def test_generic_exception(self): """ensure the generic exception can be caught""" l = [1, 2] i = mi.iter_except(l.pop, Exception) self.assertEqual(list(i), [2, 1])
def test_exact_exception(self): """ensure the exact specified exception is caught""" l = [1, 2, 3] i = mi.iter_except(l.pop, IndexError) self.assertEqual(list(i), [3, 2, 1])
async def run(self, *, timeout=120, delete_after=True, release_connection=True): """Run the interactive loop""" _validate_context(self.context) if release_connection: with contextlib.suppress(AttributeError): await self.context.release() await self.start() if self._message is None: # start() was overridden but no message was set raise RuntimeError('start() must set self._message') message = self._message triggers = self._message_callbacks.copy() task = None listeners = [] def listen(func): listeners.append(func) return self._bot.listen()(func) # XXX: Can we accomplish without context??? if self._channel.permissions_for(self.context.me).add_reactions: task = self._bot.loop.create_task(self.add_reactions()) @listen async def on_reaction_add(reaction, user): if ( not self._blocking and reaction.message.id == message.id and user.id in self._users and self.check(reaction, user) and not _trigger_cooldown .is_rate_limited(message.id, user.id) ): callback, self._blocking = self._reaction_map[reaction.emoji] cleanup = functools.partial(message.remove_reaction, reaction.emoji, user) await self._queue.put((callback, cleanup)) else: triggers.extend(self._message_fallbacks) if triggers: @listen async def on_message(msg): if ( self._blocking or msg.channel != self._channel or msg.author.id not in self._users ): return patterns, callbacks = zip(*triggers) selectors = map(re.fullmatch, patterns, itertools.repeat(msg.content)) callback = next(itertools.compress(callbacks, selectors), None) if callback is None: return if _trigger_cooldown.is_rate_limited(message.id, msg.author.id): return callback, self._blocking = callback await self._queue.put((callback, msg.delete)) try: while True: # TODO: Would async_timeout be better here? try: job = await asyncio.wait_for(self._queue.get(), timeout=timeout) except asyncio.TimeoutError: break if job is None: break callback, after = job result = await maybe_awaitable(callback, self) with contextlib.suppress(discord.HTTPException): await after() self._blocking = False if result is None: continue self._current = result # backwards compat... try: await message.edit(embed=result) except discord.NotFound: # Message was deleted break finally: for listener in listeners: self._bot.remove_listener(listener) if not (task is None or task.done()): task.cancel() consume(iter_except(self._queue.get_nowait, asyncio.QueueEmpty)) await self.cleanup(delete_after=delete_after)
def clear(self): print(self._placed_numbers) for x, y in iter_except(self._placed_numbers.pop, KeyError): self._board[y][x] = None self.stored_numbers.clear()