Skip to main content

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 files
  • OpenFolder — browse and select a folder
  • SaveFile — choose a location and filename with optional overwrite confirmation
  • messagebox — 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 — messagebox and filedialogs never 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 Pilot harness
  • 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(...) — Supports multiselect, filters, must_exist, priority
  • OpenFolder.show(...) — Folder-only selection
  • SaveFile.show(...) — Includes overwrite confirmation by default
  • All dialogs accept initial_directory, title, show_hidden, priority, and a callback

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/ERROR default to DialogPriority.HIGH; INFO/SUCCESS default to DialogPriority.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:

  1. Subclassing DialogScreenBase and setting self.priority in __init__ (defaults to DialogPriority.MEDIUM if you don't).
  2. Calling cls._present(instance) from your dialog's own show() classmethod — isolation and queueing are handled for you.

Ideas for follow-up work:

  • A DialogPriority.CRITICAL tier (above HIGH) for things like an unhandled-exception dialog that must pre-empt even a WARNING messagebox.
  • Let DialogQueue coalesce duplicate/near-identical pending requests (e.g. two identical INFO toasts queued back to back) into one.
  • A shared DialogTheme palette (the module already exists as a reserved extension point) so a future ColorPicker and the existing dialogs pull colors from one place instead of independent .tcss hex values.
  • Optional async/await-style await OpenFile.ask(...) sugar on top of the existing callback API, for call sites that would rather await a 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)

Source distribution for nannokit-dialogs 0.1.32
File Size Uploaded
nannokit_dialogs-0.1.32.tar.gz 29.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for nannokit-dialogs 0.1.32
File Interpreter ABI Platform
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

Release history Release notifications | RSS feed

This release

0.1.32 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page