1 Commits
Author SHA1 Message Date
dsql bba01fa931 refactor: rename ButtonPaginator -> DPYPaginator (keep ButtonPaginator as alias)
the paginator class is now DPYPaginator, matching the package name (dpy_paginator),
for naming consistency with the suite. ButtonPaginator is kept as a back-compat alias
(ButtonPaginator = DPYPaginator), so existing imports and call sites keep working
unchanged. both names are exported in __all__. mirrors the suite's alias convention
(aioweb Response/aiowebResponse, envelope_crypto EnvelopeCrypto/PCICrypto).

verified against discord.py 2.7.1: both names resolve to the same class, construction
via either name works, the empty-pages ValueError message updated. v0.1.6.

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-07-02 17:50:24 -04:00
4 changed files with 30 additions and 18 deletions
+11 -8
View File
@@ -9,28 +9,31 @@ buttons) behind previous / jump / next navigation, with an optional cache button
`requirements.txt`: `requirements.txt`:
``` ```
dpy_paginator @ git+ssh://git@git.rethinkstudios.io/rethink-public/dpy_paginator.git@v0.1.5 dpy_paginator @ git+ssh://git@git.rethinkstudios.io/rethink-public/dpy_paginator.git@v0.1.6
``` ```
Direct: Direct:
```bash ```bash
pip install "dpy_paginator @ git+ssh://git@git.rethinkstudios.io/rethink-public/dpy_paginator.git@v0.1.5" pip install "dpy_paginator @ git+ssh://git@git.rethinkstudios.io/rethink-public/dpy_paginator.git@v0.1.6"
``` ```
Requires `discord.py` (pulled transitively). Requires `discord.py` (pulled transitively).
Drop the `@v0.1.5` suffix from the line above to install the latest unpinned. Drop the `@v0.1.6` suffix from the line above to install the latest unpinned.
## Basic usage ## Basic usage
The paginator class is `DPYPaginator`. It is also exported as `ButtonPaginator` (a
back-compat alias) — both names refer to the same class, so either import works.
Plain pages — just navigation: Plain pages — just navigation:
```python ```python
from dpy_paginator import ButtonPaginator from dpy_paginator import DPYPaginator # or: from dpy_paginator import ButtonPaginator
pages = [discord.Embed(title=f"Page {i}") for i in range(5)] pages = [discord.Embed(title=f"Page {i}") for i in range(5)]
await ButtonPaginator(pages, author_id=ctx.author.id).start(ctx) await DPYPaginator(pages, author_id=ctx.author.id).start(ctx)
``` ```
`start()` accepts an `Interaction` or any `Messageable` (a `Context`, channel, etc.). `start()` accepts an `Interaction` or any `Messageable` (a `Context`, channel, etc.).
@@ -41,7 +44,7 @@ Navigation uses plain Unicode by default — no setup, no emoji upload required.
`emojis=` to override with custom application/guild emojis the bot can use: `emojis=` to override with custom application/guild emojis the bot can use:
```python ```python
ButtonPaginator(pages, emojis={ DPYPaginator(pages, emojis={
"previous": "<:icon_back:123...>", "previous": "<:icon_back:123...>",
"next": "<:icon_next:123...>", "next": "<:icon_next:123...>",
"cache": "<:icon_cache:123...>", "cache": "<:icon_cache:123...>",
@@ -91,7 +94,7 @@ for session in sessions:
], ],
}) })
paginator = ButtonPaginator( paginator = DPYPaginator(
pages, cache=None, timeout=900, delete_message_after=True, pages, cache=None, timeout=900, delete_message_after=True,
mentions_allowed=discord.AllowedMentions.none(), ephemeral=True, mentions_allowed=discord.AllowedMentions.none(), ephemeral=True,
page_text="Session {} of {}", page_text="Session {} of {}",
@@ -124,7 +127,7 @@ for group in groups:
pages.append(build_embed(group)) pages.append(build_embed(group))
cache.append(" ".join(f"<@{uid}>" for uid in group["user_ids"])) cache.append(" ".join(f"<@{uid}>" for uid in group["user_ids"]))
await ButtonPaginator(pages, cache=cache, cache_sleep=1.0).start(ctx) await DPYPaginator(pages, cache=cache, cache_sleep=1.0).start(ctx)
``` ```
Omit `cache` or pass `None`/`[]` and the button never appears. When set, `cache` Omit `cache` or pass `None`/`[]` and the button never appears. When set, `cache`
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project] [project]
name = "dpy_paginator" name = "dpy_paginator"
version = "0.1.5" version = "0.1.6"
description = "Button-navigated paginator for discord.py — config-free, injectable emojis, installable." description = "Button-navigated paginator for discord.py — config-free, injectable emojis, installable."
requires-python = ">=3.10" requires-python = ">=3.10"
dependencies = [ dependencies = [
+2 -2
View File
@@ -1,3 +1,3 @@
from .dpy_paginator import ButtonPaginator, JumpToPageModal, DEFAULT_EMOJIS, Page from .dpy_paginator import DPYPaginator, ButtonPaginator, JumpToPageModal, DEFAULT_EMOJIS, Page
__all__ = ["ButtonPaginator", "JumpToPageModal", "DEFAULT_EMOJIS", "Page"] __all__ = ["DPYPaginator", "ButtonPaginator", "JumpToPageModal", "DEFAULT_EMOJIS", "Page"]
+16 -7
View File
@@ -5,15 +5,15 @@ a discord.ui.View that paginates mixed content (strings, embeds, files,
attachments, or dicts of mixed content with custom buttons) behind attachments, or dicts of mixed content with custom buttons) behind
previous / jump / next navigation, with an optional cache button. previous / jump / next navigation, with an optional cache button.
from dpy_paginator import ButtonPaginator from dpy_paginator import DPYPaginator # or ButtonPaginator, an alias
pages = [discord.Embed(title=f"Page {i}") for i in range(5)] pages = [discord.Embed(title=f"Page {i}") for i in range(5)]
await ButtonPaginator(pages, author_id=ctx.author.id).start(ctx) await DPYPaginator(pages, author_id=ctx.author.id).start(ctx)
emojis: navigation uses plain unicode by default (no setup). pass emojis= to emojis: navigation uses plain unicode by default (no setup). pass emojis= to
override with custom application/guild emojis the bot can use: override with custom application/guild emojis the bot can use:
ButtonPaginator(pages, emojis={ DPYPaginator(pages, emojis={
"previous": "<:icon_back:123...>", "previous": "<:icon_back:123...>",
"next": "<:icon_next:123...>", "next": "<:icon_next:123...>",
"cache": "<:icon_cache:123...>", "cache": "<:icon_cache:123...>",
@@ -111,7 +111,7 @@ class _CustomButton(discord.ui.Button):
class JumpToPageModal(discord.ui.Modal, title="Jump to Page"): class JumpToPageModal(discord.ui.Modal, title="Jump to Page"):
"""modal that lets a user jump to a specific page""" """modal that lets a user jump to a specific page"""
def __init__(self, paginator: "ButtonPaginator"): def __init__(self, paginator: "DPYPaginator"):
super().__init__() super().__init__()
self.paginator = paginator self.paginator = paginator
self.page_number = discord.ui.TextInput( self.page_number = discord.ui.TextInput(
@@ -139,8 +139,12 @@ class JumpToPageModal(discord.ui.Modal, title="Jump to Page"):
) )
class ButtonPaginator(Generic[PageT_co], discord.ui.View): class DPYPaginator(Generic[PageT_co], discord.ui.View):
"""button-navigated paginator supporting mixed page content and custom buttons""" """button-navigated paginator supporting mixed page content and custom buttons
also importable as `ButtonPaginator` (a back-compat alias defined below); both
names refer to this same class.
"""
message: Optional[Union[discord.Message, discord.WebhookMessage]] = None message: Optional[Union[discord.Message, discord.WebhookMessage]] = None
@@ -177,7 +181,7 @@ class ButtonPaginator(Generic[PageT_co], discord.ui.View):
""" """
super().__init__(timeout=timeout) super().__init__(timeout=timeout)
if not pages: if not pages:
raise ValueError("ButtonPaginator requires at least one page") raise ValueError("DPYPaginator requires at least one page")
if per_page < 1: if per_page < 1:
# per_page <= 0 would ZeroDivisionError (==0) or yield a negative max_pages # per_page <= 0 would ZeroDivisionError (==0) or yield a negative max_pages
# (<0) at the divmod below; fail loud like the other construction guards # (<0) at the divmod below; fail loud like the other construction guards
@@ -513,3 +517,8 @@ class ButtonPaginator(Generic[PageT_co], discord.ui.View):
# on_timeout runs as a fire-and-forget task; a transient delete failure must # on_timeout runs as a fire-and-forget task; a transient delete failure must
# not surface as an unretrieved-task traceback on a best-effort cleanup # not surface as an unretrieved-task traceback on a best-effort cleanup
log.warning("paginator on_timeout: failed to delete message", exc_info=True) log.warning("paginator on_timeout: failed to delete message", exc_info=True)
# back-compat alias: the class was originally named ButtonPaginator; DPYPaginator is
# the canonical name (matching the package), both refer to the same class
ButtonPaginator = DPYPaginator