NannoKit.Dialogs
Official dialogs extension for SuperNanno — a modern, lightweight set of file and message dialogs built for Textual applications.
NannoKit.Dialogs provides clean, high-level APIs for common user interactions:
OpenFile— select one or multiple filesOpenFolder— browse and select a folderSaveFile— choose a location and filename with optional overwrite confirmationmessagebox— flexible notification and confirmation dialogs
Designed to integrate seamlessly into SuperNanno and work standalone in any Textual app.
Features
- Automatic resolution of the running Textual
App(no manual passing required in most cases) - Full keyboard navigation and mouse support
- Filterable directory tree (hidden files, glob patterns)
- Editable location field for quick path navigation
- Multiselect support in OpenFile
- Validation (
must_exist) with inline feedback - Consistent styling and Escape-to-cancel behavior
- Priority-aware isolation —
messageboxandfiledialogsnever interrupt or replace each other; see Isolation & Priority below - Composable — dialogs can call each other internally (e.g.
SaveFile's overwrite prompt) - Thorough test coverage with Textual's
Pilotharness - Installable as a standalone package or as part of the SuperNanno ecosystem
Installation
pip install nannokit.dialogs
To also install SuperNanno core (when available):
pip install "nannokit.dialogs[supernanno]"
Quick Start
from nannokit.dialogs import OpenFile, OpenFolder, SaveFile, messagebox
from pathlib import Path
# Open file(s)
OpenFile.show(
initial_directory=".",
filters=["*.py", "*.toml", "*.md"],
callback=lambda path: print("Selected:", path),
)
# Open folder
OpenFolder.show(
initial_directory=".",
callback=lambda folder: print("Folder:", folder),
)
# Save file
SaveFile.show(
default_filename="untitled.txt",
callback=lambda path: print("Save to:", path),
)
# Message dialog
messagebox.show(
"Save changes before closing?",
title="SuperNanno",
buttons=messagebox.buttons.YES_NO_CANCEL,
type=messagebox.type.WARNING,
callback=lambda choice: print("Choice:", choice),
)
Integration with SuperNanno
In your main App class, attach the dialog manager once (recommended):
from textual.app import App
from nannokit.dialogs.core import DialogManager
class SuperNannoApp(App):
def on_mount(self) -> None:
DialogManager.attach(self)
After this, you can call any dialog from event handlers, actions, or bindings without additional setup.
Isolation & Priority
messagebox and filedialogs are completely isolated from one
another: neither can silently cancel, replace, or bury the other.
Every dialog carries a priority tier, and a shared DialogQueue
decides what happens when a new dialog is requested while another is
already on screen:
| Situation | Behaviour |
|---|---|
| Nothing currently showing | The dialog is shown immediately (same as always). |
| A lower-priority dialog is showing | The new one is stacked on top right away — Textual's screen stack keeps the interrupted dialog's state fully intact underneath, so it just picks up where it left off once the new one is dismissed. |
| An equal or higher-priority dialog is showing | The new one is queued and shown automatically as soon as the current one is dismissed — it never interrupts, cancels, or is dropped. |
Default priority tiers (nannokit.dialogs.core.DialogPriority):
class DialogPriority:
LOW = 30 # messagebox.type.INFO / SUCCESS
MEDIUM = 50 # OpenFile, OpenFolder, SaveFile, OpenPath
HIGH = 100 # messagebox.type.WARNING / ERROR
This is why SaveFile's built-in overwrite confirmation (a WARNING
messagebox, HIGH) always appears on top of the SaveFile dialog
that spawned it (MEDIUM) and must be answered before SaveFile can
proceed — and, symmetrically, why an informational messagebox.show()
fired from a background task never yanks focus away from a file
dialog the user is actively using.
You normally don't need to think about any of this — it's automatic.
If you do need to override a dialog's default tier for a specific
call, every .show(...) accepts an explicit priority=:
from nannokit.dialogs import messagebox
from nannokit.dialogs.core import DialogPriority
# An INFO box that must still interrupt an open file dialog:
messagebox.show(
"Critical background task failed.",
type=messagebox.type.INFO,
priority=DialogPriority.HIGH,
callback=on_result,
)
# ...or the equivalent, priority-first convenience form:
messagebox.show_with_priority(
DialogPriority.HIGH,
"Critical background task failed.",
type=messagebox.type.INFO,
callback=on_result,
)
OpenFile, OpenFolder, SaveFile, and OpenPath all accept the
same priority= kwarg and expose the same show_with_priority(...)
helper.
API Overview
File Dialogs
OpenFile.show(...)— Supportsmultiselect,filters,must_exist,priorityOpenFolder.show(...)— Folder-only selectionSaveFile.show(...)— Includes overwrite confirmation by default- All dialogs accept
initial_directory,title,show_hidden,priority, and acallback
MessageBox
messagebox.show(
message: str,
title: str = "Message",
buttons: list[str] | None = None,
type: str = messagebox.type.INFO,
callback: Callable[[str | None], None] | None = None,
priority: int | None = None,
)
- Available button presets:
OK,OK_CANCEL,YES_NO,YES_NO_CANCEL,RETRY_CANCEL, etc. - Available types:
INFO,WARNING,ERROR,SUCCESS.WARNING/ERRORdefault toDialogPriority.HIGH;INFO/SUCCESSdefault toDialogPriority.LOW.
Package Structure
nannokit/dialogs/
├── core/ # Shared manager, priority queue, base screen, and utilities
│ ├── manager.py # DialogManager - resolves the running App
│ ├── queue.py # DialogQueue - priority-aware presentation scheduler
│ ├── priority.py # DialogPriority - LOW / MEDIUM / HIGH tiers
│ └── base.py # DialogScreenBase - shared ModalScreen plumbing
├── messagebox/ # Message dialog implementation
├── filedialogs/ # OpenFile, OpenFolder, SaveFile + shared tree
└── styles/ # TCSS stylesheets
Development
# Install in editable mode with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
Roadmap / Extending
The priority/queue architecture was designed so that adding a new
dialog (e.g. a ColorPicker) only requires:
- Subclassing
DialogScreenBaseand settingself.priorityin__init__(defaults toDialogPriority.MEDIUMif you don't). - Calling
cls._present(instance)from your dialog's ownshow()classmethod — isolation and queueing are handled for you.
Ideas for follow-up work:
- A
DialogPriority.CRITICALtier (aboveHIGH) for things like an unhandled-exception dialog that must pre-empt even aWARNINGmessagebox. - Let
DialogQueuecoalesce duplicate/near-identical pending requests (e.g. two identical INFO toasts queued back to back) into one. - A shared
DialogThemepalette (the module already exists as a reserved extension point) so a futureColorPickerand the existing dialogs pull colors from one place instead of independent.tcsshex values. - Optional async/await-style
await OpenFile.ask(...)sugar on top of the existing callback API, for call sites that would ratherawaita result than provide a callback.
License
BSD 3-Clause License — see LICENSE for details.
Part of the SuperNanno ecosystem. Built to make powerful Textual applications even easier to develop.
Release files for nannokit-dialogs 0.1.32
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nannokit_dialogs-0.1.32.tar.gz | 29.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nannokit_dialogs-0.1.32-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 68.6 kB
Release files / nannokit_dialogs-0.1.32.tar.gz
| Download URL | nannokit_dialogs-0.1.32.tar.gz |
|---|---|
| Size | 29.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a11e0ad9645a3502e17d7c2e9b3cfaa231b6ee0255f6be723bb6b82a91750ce9
|
|
BLAKE2b-256 checksum How to use checksums |
201c78a221f309f9d570309977d1fc6b8667c5faa6a8ab0e10c0ad906e3e4abe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/5.1.1 CPython/3.9.0
|
Release files / nannokit_dialogs-0.1.32-py3-none-any.whl
| Download URL | nannokit_dialogs-0.1.32-py3-none-any.whl |
|---|---|
| Size | 38.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e8b10030c34e60c3a25f8e3e2b8a627662634199d7f40a268ff1aeb4beb32af2
|
|
BLAKE2b-256 checksum How to use checksums |
08d3ec65a4aac620634cbdb9c18c31fdc83a0132d740dede4fb59e2f0911e8ab
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/5.1.1 CPython/3.9.0
|