async def jsk_cat(self, ctx: commands.Context, argument: str): """ Read out a file, using syntax highlighting if detected. Lines and linespans are supported by adding '#L12' or '#L12-14' etc to the end of the filename. """ match = self.__cat_line_regex.search(argument) if not match: # should never happen return await ctx.send("Couldn't parse this input.") path = match.group(1) line_span = None if match.group(2): start = int(match.group(2)) line_span = (start, int(match.group(3) or start)) if not os.path.exists(path) or os.path.isdir(path): return await ctx.send(f"`{path}`: No file by that name.") size = os.path.getsize(path) if size <= 0: return await ctx.send( f"`{path}`: Cowardly refusing to read a file with no size stat" f" (it may be empty, endless or inaccessible).") if size > 50 * (1024**2): return await ctx.send( f"`{path}`: Cowardly refusing to read a file >50MB.") try: with open(path, "rb") as file: paginator = FilePaginator(file, line_span=line_span, max_size=1985) except UnicodeDecodeError: return await ctx.send( f"`{path}`: Couldn't determine the encoding of this file.") except ValueError as exc: return await ctx.send(f"`{path}`: Couldn't read this file, {exc}") interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) await interface.send_to(ctx)
def test_file_paginator(): base_text = inspect.cleandoc(""" #!/usr/bin/env python # -*- coding: utf-8 -*- pass # \u3088\u308d\u3057\u304f """) # test standard encoding pages = FilePaginator(BytesIO(base_text.encode("utf-8"))).pages assert len(pages) == 1 assert pages[0] == f"```python\n{base_text}\n```" # test linespan pages = FilePaginator(BytesIO(base_text.encode("utf-8")), line_span=(2, 2)).pages assert len(pages) == 1 assert pages[0] == "```python\n# -*- coding: utf-8 -*-\n```" # test reception to encoding hint base_text = inspect.cleandoc(""" #!/usr/bin/env python # -*- coding: cp932 -*- pass # \u3088\u308d\u3057\u304f """) pages = FilePaginator(BytesIO(base_text.encode("cp932"))).pages assert len(pages) == 1 assert pages[0] == f"```python\n{base_text}\n```" # test without encoding hint with pytest.raises(UnicodeDecodeError): FilePaginator(BytesIO("\u3088\u308d\u3057\u304f".encode("cp932"))) # test with wrong encoding hint with pytest.raises(UnicodeDecodeError): FilePaginator( BytesIO("-*- coding: utf-8 -*-\n\u3088\u308d\u3057\u304f".encode( "cp932"))) # test OOB with pytest.raises(ValueError): FilePaginator(BytesIO("one\ntwo\nthree\nfour".encode('utf-8')), line_span=(-1, 20))
async def test_paginator_interface(): bot = commands.Bot('?') with open(__file__, 'rb') as file: paginator = FilePaginator(file, max_size=200) interface = PaginatorInterface(bot, paginator) assert interface.pages == paginator.pages assert interface.page_count == len(paginator.pages) assert interface.page_size > 200 assert interface.page_size < interface.max_page_size send_kwargs = interface.send_kwargs assert isinstance(send_kwargs, dict) assert 'content' in send_kwargs content = send_kwargs['content'] assert isinstance(content, str) assert len(content) <= interface.page_size assert interface.display_page == 0 # pages have been closed, so adding a line should make a new page old_page_count = interface.page_count await interface.add_line('a' * 150) assert interface.page_count > old_page_count # push the page to the end (rounded into bounds) interface.display_page = 999 old_display_page = interface.display_page assert interface.pages == paginator.pages # page closed, so create new page await interface.add_line('b' * 150) # ensure page has followed tail assert interface.display_page > old_display_page # testing with embed interface embed_interface = PaginatorEmbedInterface(bot, paginator) assert embed_interface.pages[0] == interface.pages[0] send_kwargs = embed_interface.send_kwargs assert isinstance(send_kwargs, dict) assert 'embed' in send_kwargs embed = send_kwargs['embed'] assert isinstance(embed, discord.Embed) description = embed.description assert content.startswith(description) # check for raise on too large page size with pytest.raises(ValueError): PaginatorInterface(None, commands.Paginator(max_size=2000)) # check for raise on not-paginator with pytest.raises(TypeError): PaginatorInterface(None, 4) paginator = commands.Paginator(max_size=100) for _ in range(100): paginator.add_line("test text") # test interfacing with utils.mock_ctx(bot) as ctx: interface = PaginatorInterface(bot, paginator) assert not interface.closed await interface.send_to(ctx) await asyncio.sleep(0.1) await interface.add_line("test text") assert interface.page_count > 1 assert not interface.closed interface.message.id = utils.sentinel() current_page = interface.display_page payload = { 'message_id': interface.message.id, 'user_id': ctx.author.id, 'channel_id': ctx.channel.id, 'guild_id': ctx.guild.id } # push right button emoji = discord.PartialEmoji( animated=False, name="\N{BLACK RIGHT-POINTING TRIANGLE}", id=None ) bot.dispatch( 'raw_reaction_add', discord.RawReactionActionEvent(payload, emoji, 'REACTION_ADD') if discord.version_info >= (1, 3) else discord.RawReactionActionEvent(payload, emoji) ) await asyncio.sleep(0.1) assert interface.display_page > current_page assert not interface.closed current_page = interface.display_page # push left button emoji = discord.PartialEmoji( animated=False, name="\N{BLACK LEFT-POINTING TRIANGLE}", id=None ) bot.dispatch( 'raw_reaction_add', discord.RawReactionActionEvent(payload, emoji, 'REACTION_ADD') if discord.version_info >= (1, 3) else discord.RawReactionActionEvent(payload, emoji) ) await asyncio.sleep(0.1) assert interface.display_page < current_page assert not interface.closed # push last page button emoji = discord.PartialEmoji( animated=False, name="\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}", id=None ) bot.dispatch( 'raw_reaction_add', discord.RawReactionActionEvent(payload, emoji, 'REACTION_ADD') if discord.version_info >= (1, 3) else discord.RawReactionActionEvent(payload, emoji) ) await asyncio.sleep(0.1) assert interface.display_page == interface.page_count - 1 assert not interface.closed # push first page button emoji = discord.PartialEmoji( animated=False, name="\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}", id=None ) bot.dispatch( 'raw_reaction_add', discord.RawReactionActionEvent(payload, emoji, 'REACTION_ADD') if discord.version_info >= (1, 3) else discord.RawReactionActionEvent(payload, emoji) ) await asyncio.sleep(0.1) assert interface.display_page == 0 assert not interface.closed # push close button emoji = discord.PartialEmoji( animated=False, name="\N{BLACK SQUARE FOR STOP}", id=None ) bot.dispatch( 'raw_reaction_add', discord.RawReactionActionEvent(payload, emoji, 'REACTION_ADD') if discord.version_info >= (1, 3) else discord.RawReactionActionEvent(payload, emoji) ) await asyncio.sleep(0.1) assert interface.closed ctx.send.coro.return_value.delete.assert_called_once() # test resend, no delete with utils.mock_ctx(bot) as ctx: interface = PaginatorInterface(bot, paginator) assert not interface.closed await interface.send_to(ctx) await asyncio.sleep(0.1) await interface.add_line("test text") assert interface.page_count > 1 assert not interface.closed # resend await interface.send_to(ctx) await asyncio.sleep(0.1) await interface.add_line("test text") ctx.send.coro.return_value.delete.assert_not_called() interface.task.cancel() await asyncio.sleep(0.1) assert interface.closed # test resend, delete with utils.mock_ctx(bot) as ctx: interface = PaginatorInterface(bot, paginator, delete_message=True) assert not interface.closed await interface.send_to(ctx) await asyncio.sleep(0.1) await interface.add_line("test text") assert interface.page_count > 1 assert not interface.closed # resend await interface.send_to(ctx) await asyncio.sleep(0.1) await interface.add_line("test text") ctx.send.coro.return_value.delete.assert_called_once() interface.task.cancel() await asyncio.sleep(0.1) assert interface.closed
def test_paginator_interface(self): bot = commands.Bot('?') with open(__file__, 'rb') as fp: paginator = FilePaginator(fp, max_size=200) interface = PaginatorInterface(bot, paginator) self.assertEqual(interface.pages, paginator.pages) self.assertEqual(interface.page_count, len(paginator.pages)) self.assertGreater(interface.page_size, 200) self.assertLess(interface.page_size, interface.max_page_size) send_kwargs = interface.send_kwargs self.assertIsInstance(send_kwargs, dict) self.assertIn('content', send_kwargs) content = send_kwargs['content'] self.assertIsInstance(content, str) self.assertLessEqual(len(content), interface.page_size) self.assertEqual(interface.display_page, 0) # pages have been closed, so adding a line should make a new page old_page_count = interface.page_count bot.loop.run_until_complete(interface.add_line('a' * 150)) self.assertGreater(interface.page_count, old_page_count) # push the page to the end (rounded into bounds) interface.display_page = 999 old_display_page = interface.display_page self.assertEqual(interface.pages, paginator.pages) # page closed, so create new page bot.loop.run_until_complete(interface.add_line('b' * 150)) # ensure page has followed tail self.assertGreater(interface.display_page, old_display_page) # testing with embed interface embed_interface = PaginatorEmbedInterface(bot, paginator) self.assertEqual(embed_interface.pages[0], interface.pages[0]) send_kwargs = embed_interface.send_kwargs self.assertIsInstance(send_kwargs, dict) self.assertIn('embed', send_kwargs) embed = send_kwargs['embed'] self.assertIsInstance(embed, discord.Embed) description = embed.description self.assertTrue(content.startswith(description)) # check for raise on too large page size raised = False try: PaginatorInterface(None, commands.Paginator(max_size=2000)) except ValueError: raised = True self.assertTrue(raised) # check for raise on not-paginator raised = False try: PaginatorInterface(None, 4) except TypeError: raised = True self.assertTrue(raised) bot.loop.run_until_complete(bot.close())
def test_file_paginator(self): base_text = inspect.cleandoc(""" #!/usr/bin/env python # -*- coding: utf-8 -*- pass # \u3088\u308d\u3057\u304f """) # test standard encoding pages = FilePaginator(BytesIO(base_text.encode("utf-8"))).pages self.assertEqual(len(pages), 1) self.assertEqual(pages[0], f"```python\n{base_text}\n```") # test linespan pages = FilePaginator(BytesIO(base_text.encode("utf-8")), line_span=(2, 2)).pages self.assertEqual(len(pages), 1) self.assertEqual(pages[0], f"```python\n# -*- coding: utf-8 -*-\n```") # test reception to encoding hint base_text = inspect.cleandoc(""" #!/usr/bin/env python # -*- coding: cp932 -*- pass # \u3088\u308d\u3057\u304f """) pages = FilePaginator(BytesIO(base_text.encode("cp932"))).pages self.assertEqual(len(pages), 1) self.assertEqual(pages[0], f"```python\n{base_text}\n```") # test without encoding hint raised = False try: FilePaginator(BytesIO("\u3088\u308d\u3057\u304f".encode("cp932"))) except UnicodeDecodeError: raised = True self.assertTrue(raised) # test with wrong encoding hint raised = False try: FilePaginator( BytesIO( "-*- coding: utf-8 -*-\n\u3088\u308d\u3057\u304f".encode( "cp932"))) except UnicodeDecodeError: raised = True self.assertTrue(raised) # test OOB raised = False try: FilePaginator(BytesIO("one\ntwo\nthree\nfour".encode('utf-8')), line_span=(-1, 20)) except ValueError: raised = True self.assertTrue(raised)