An extension module to make reaction based menus with disnake

Overview

disnake-ext-menus

An experimental extension menu that makes working with reaction menus a bit easier.

Installing

python -m pip install -U disnake-ext-menus

Getting Started

To whet your appetite, the following examples show the fundamentals on how to create menus.

The first example shows a basic menu that has a stop button and two reply buttons:

from disnake.ext import menus

class MyMenu(menus.Menu):
    async def send_initial_message(self, ctx, channel):
        return await channel.send(f'Hello {ctx.author}')

    @menus.button('\N{THUMBS UP SIGN}')
    async def on_thumbs_up(self, payload):
        await self.message.edit(content=f'Thanks {self.ctx.author}!')

    @menus.button('\N{THUMBS DOWN SIGN}')
    async def on_thumbs_down(self, payload):
        await self.message.edit(content=f"That's not nice {self.ctx.author}...")

    @menus.button('\N{BLACK SQUARE FOR STOP}\ufe0f')
    async def on_stop(self, payload):
        self.stop()

Now, within a command we just instantiate it and we start it like so:

@bot.command()
async def menu_example(ctx):
    m = MyMenu()
    await m.start(ctx)

If an error happens then an exception of type menus.MenuError is raised.

This second example shows a confirmation menu and how we can compose it and use it later:

from disnake.ext import menus

class Confirm(menus.Menu):
    def __init__(self, msg):
        super().__init__(timeout=30.0, delete_message_after=True)
        self.msg = msg
        self.result = None

    async def send_initial_message(self, ctx, channel):
        return await channel.send(self.msg)

    @menus.button('\N{WHITE HEAVY CHECK MARK}')
    async def do_confirm(self, payload):
        self.result = True
        self.stop()

    @menus.button('\N{CROSS MARK}')
    async def do_deny(self, payload):
        self.result = False
        self.stop()

    async def prompt(self, ctx):
        await self.start(ctx, wait=True)
        return self.result

Then when it comes time to use it we can do it like so:

@bot.command()
async def delete_things(ctx):
    confirm = await Confirm('Delete everything?').prompt(ctx)
    if confirm:
        await ctx.send('deleted...')

Pagination

The meat of the library is the Menu class but a MenuPages class is provided for the common use case of actually making a pagination session.

The MenuPages works similar to Menu except things are separated into a PageSource. The actual MenuPages rarely needs to be modified, instead we pass in a PageSource that deals with the data representation and formatting of the data we want to paginate.

The library comes with a few built-in page sources:

  • ListPageSource: The basic source that deals with a list of items.
  • GroupByPageSource: A page source that groups a list into multiple sublists similar to itertools.groupby.
  • AsyncIteratorPageSource: A page source that works with async iterators for lazy fetching of data.

None of these page sources deal with formatting of data, leaving that up to you.

For the sake of example, here's a basic list source that is paginated:

from disnake.ext import menus

class MySource(menus.ListPageSource):
    def __init__(self, data):
        super().__init__(data, per_page=4)

    async def format_page(self, menu, entries):
        offset = menu.current_page * self.per_page
        return '\n'.join(f'{i}. {v}' for i, v in enumerate(entries, start=offset))

# somewhere else:
pages = menus.MenuPages(source=MySource(range(1, 100)), clear_reactions_after=True)
await pages.start(ctx)

The format_page can return either a str for content, disnake.Embed for an embed, or a dict to pass into the kwargs of Message.edit.

Some more examples using GroupByPageSource:

from disnake.ext import menus

class Test:
    def __init__(self, key, value):
        self.key = key
        self.value = value

data = [
    Test(key=key, value=value)
    for key in ['test', 'other', 'okay']
    for value in range(20)
]

class Source(menus.GroupByPageSource):
    async def format_page(self, menu, entry):
        joined = '\n'.join(f'{i}. 
   
    {
    v.
    value
    }
   >' for i, v in enumerate(entry.items, start=1))
        return f'**{entry.key}**\n{joined}\nPage {menu.current_page + 1}/{self.get_max_pages()}'

pages = menus.MenuPages(source=Source(data, key=lambda t: t.key, per_page=12), clear_reactions_after=True)
await pages.start(ctx)

Another one showing AsyncIteratorPageSource:

from disnake.ext import menus

class Test:
    def __init__(self, value):
        self.value = value

    def __repr__(self):
        return f'
   
    {
    self.
    value
    }
   >'

async def generate(number):
    for i in range(number):
        yield Test(i)

class Source(menus.AsyncIteratorPageSource):
    def __init__(self):
        super().__init__(generate(9), per_page=4)

    async def format_page(self, menu, entries):
        start = menu.current_page * self.per_page
        return f'\n'.join(f'{i}. {v!r}' for i, v in enumerate(entries, start=start))

pages = menus.MenuPages(source=Source(), clear_reactions_after=True)
await pages.start(ctx)
Performance monitoring and testing of OpenStack

Browbeat Browbeat is a performance tuning and analysis tool for OpenStack. Browbeat is free, Open Source software. Analyze and tune your Cloud for opt

cloud-bulldozer 83 Dec 14, 2022
Basit bir cc generator'ü.

Basit bir cc generator'ü. Setup What To Do; Python Installation We install python from CLICK Generator Board After installing the file and python, we

Lâving 7 Jan 09, 2022
Bazel rules to install Python dependencies with Poetry

rules_python_poetry Bazel rules to install Python dependencies from a Poetry project. Works with native Python rules for Bazel. Getting started Add th

Martin Liu 7 Dec 15, 2021
An Notifier Program that Notifies you to relax your eyes Every 15 Minutes👀

Every 15 Minutes ⌛ Every 15 Minutes is an application that is used to Notify you to Relax your eyes Every 15 Minutes, This is fully made with Python a

FSP Gang s' YT 2 Oct 18, 2021
Bootcamp de Introducción a la Programación. Módulo 6: Matemáticas Discretas

Módulo 6: Matemáticas Discretas Última actualización: 12 de marzo Irónicamente, las matemáticas discretas son las matemáticas que lo cuentan todo. Si

Cynthia Castillo 34 Sep 29, 2022
The fetch of the delegator list and the input of the epoch nonce need to be done independently

raffle The fetch of the delegator list and the input of the epoch nonce need to be done independently. Get the list of delegators at the epoch change.

1 Dec 15, 2021
High-level bindings to the Valhalla framework.

Valhalla for Python This spin-off project simply offers improved Python bindings to the fantastic Valhalla project. Installation pip install valhalla

GIS • OPS 20 Dec 13, 2022
Sample microservices application demo

Development mode docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d or export COMPOSE_FILE='docker-compose.yml:docker-compose.dev.ym

Konstantinos Bairaktaris 1 Nov 14, 2021
addon for blender to import mocap data from tools like easymocap, frankmocap and Vibe

b3d_mocap_import addon for blender to import mocap data from tools like easymocap, frankmocap and Vibe ==================VIBE================== To use

Carlos Barreto 97 Dec 07, 2022
Hacking and Learning consistently for 100 days straight af.

#100DaysOfHacking Hacking and Learning consistently for 100 days straight af. [yes, no breaks except mental-break ones, Obviously.] This Repo is one s

FENIL SHAH 17 Sep 09, 2022
A Blender addon for VSE that auto-adjusts video strip's length, if speed effect is applied.

Blender VSE Speed Adjust Addon When using Video Sequence Editor in Blender, the speed effect strip doesn't auto-adjusts clip length when changing its

Arpit Srivastava 2 Jan 18, 2022
Reproducible nvim completion framework benchmarks.

Nvim.Bench Reproducible nvim completion framework benchmarks. Runs inside Docker. Fair and balanced Methodology Note: for all "randomness", they are g

i love my dog 14 Nov 20, 2022
Simple package to make requests throughout Tor with circuit renewal.

AutoTor Table of Contents About the Project Contents Dependencies Getting Started Installation Coding Contributing About the Project Simple package to

Salvador Belenguer 6 Jan 01, 2023
A simple assembly- and brainfuck-inspired stack-based language

asm-stackfuck A simple assembly- and brainfuck-inspired stack-based language. The language has a few goals: Be stack-based Look like assembly Have a s

Nils Trinity 1 Feb 06, 2022
Trackthis - This library can be used to track USPS and UPS shipments.

Trackthis - This library can be used to track USPS and UPS shipments. It has the option of returning the raw API response, or optionally, it can be used to standardize the USPS and UPS responses so t

Aaron Guzman 0 Mar 29, 2022
Demo of using DataLoader to prevent out of memory

Demo of using DataLoader to prevent out of memory

3 Jun 25, 2022
Курс про техническое совершенство для нетехнарей

Technical Excellence 101 Курс про техническое совершенство для нетехнарей. Этот курс представлят из себя серию воркшопов, при помощи которых можно объ

Anton Bevzuk 11 Nov 13, 2022
A project to work with databases in 4 worksheets, insert, update, select, delete using Python and MySqI

A project to work with databases in 4 worksheets, insert, update, select, delete using Python and MySqI As a small project for school or college hope it is useful

Sina Org 1 Jan 11, 2022
Unofficial Python Library to communicate with SESAME 3 series products from CANDY HOUSE, Inc.

pysesame3 Unofficial Python Library to communicate with SESAME 3 series products from CANDY HOUSE, Inc. This project aims to control SESAME 3 series d

Masaki Tagawa 18 Dec 12, 2022
CNKD - Minimalistic Windows ransomware written in Python

CNKD Minimalistic Windows ransomware written in Python (Still a work in progress

Alex 2 May 27, 2022