Skip to main content

A minimal access to GUI, TUI, CLI and config

Project description

Mininterface – access to GUI, TUI, web, CLI and config files

Build Status Downloads

Write the program core, do not bother with the input/output.

Hello world example: GUI window Hello world example: TUI fallback

Check out the code, which is surprisingly short, that displays such a window or its textual fallback.

from dataclasses import dataclass
from mininterface import run

@dataclass
class Env:
    """ This calculates something. """

    my_flag: bool = False
    """ This switches the functionality """

    my_number: int = 4
    """ This number is very important """

if __name__ == "__main__":
    m = run(Env, title="My application")
    m.form()
    # Attributes are suggested by the IDE
    # along with the hint text 'This number is very important'.
    print(m.env.my_number)

Contents

You got CLI

It was all the code you need. No lengthy blocks of code imposed by an external dependency. Besides the GUI/TUI/web, you receive powerful YAML-configurable CLI parsing.

$ ./program.py --help
usage: program.py [-h] [-v] [--my-flag | --no-my-flag] [--my-number INT]

This calculates something.

╭─ options ───────────────────────────────────────────────────────────────╮
│ -h, --help             show this help message and exit                  │
│ -v, --verbose          Verbosity level. Can be used twice to increase.  │
│ --my-flag, --no-my-flag                                                 │
│                        This switches the functionality (default: False) │
│ --my-number INT        This number is very important (default: 4)       │
╰─────────────────────────────────────────────────────────────────────────╯

You got config file management

Loading config file is a piece of cake. Alongside program.py, write some of its arguments to program.yaml. They are seamlessly taken as defaults.

my_number: 555
$ program.py --help
...
│ --my-number INT        This number is very important (default: 555)     

You got dialogs

Check out several useful methods to handle user dialogs. Here we bound the interface to a with statement that redirects stdout directly to the window.

with run(Env) as m:
    print(f"Your important number is {m.env.my_number}")
    boolean = m.confirm("Is that alright?")

Small window with the text 'Your important number' The same in terminal'

Background

Wrapper between various libraries that provide a user interface.

Writing a small and useful program might be a task that takes fifteen minutes. Adding a CLI to specify the parameters is not so much overhead. But building a simple GUI around it? HOURS! Hours spent on researching GUI libraries, wondering why the Python desktop app ecosystem lags so far behind the web world. All you need is a few input fields validated through a clickable window... You do not deserve to add hundred of lines of the code just to define some editable fields. Mininterface is here to help.

The config variables needed by your program are kept in cozy dataclasses. Write less! The syntax of tyro does not require any overhead (as its argparse alternatives do). You just annotate a class attribute, append a simple docstring and get a fully functional application:

  • Call it as program.py --help to display full help.
  • Use any flag in CLI: program.py --my-flag causes env.my_flag be set to True.
  • The main benefit: Launch it without parameters as program.py to get a fully working window with all the flags ready to be edited.
  • Running on a remote machine? Automatic regression to the text interface.
  • Or access your program via web browser.

Installation

Install with a single command from PyPi.

pip install "mininterface[all]<2"  # GPLv3 and compatible

Bundles

There are various bundles. We mark the least permissive licence in the bundle.

bundle size licence description
mininterface 1 MB LGPL minimal – only text dialogs
mininterface[basic] 25 MB LGPL CLI, GUI, TUI
mininterface[web] 40 MB LGPL including WebInterface
mininterface[img] 40 MB LGPL images
mininterface[tui] 40 MB LGPL images
mininterface[gui] 70 MB GPL images, combobox, calendar
mininterface[ui] 90 MB GPL full installation
mininterface[all] 90 MB GPL full installation, same as ui, reserved for future use (big dependencies, optional interfaces)

Apart from the minimal bundle (which lacks CLI and dataclass support), they have the same functionality, differring only in the user experience.

!!! tip For automated testing (e.g., in CI environments), the mininterface[basic] bundle is sufficient.

MacOS GUI

If the GUI does not work on MacOS, you might need to launch: brew install python-tk

Docs

See the docs overview at https://cz-nic.github.io/mininterface/.

Gallery

These projects have the code base reduced thanks to the mininterface:

  • deduplidog – Find duplicates in a scattered directory structure
  • touch-timestamp – A powerful dialog to change the files' timestamp

Examples

Hello world

Take a look at the following example.

  1. We define any Env class.
  2. Then, we initialize mininterface with [run(Env)][mininterface.run] – the missing fields will be prompted for
  3. Then, we use various dialog methods, like [confirm][mininterface.Mininterface.confirm], [select][mininterface.Mininterface.select] or [form][mininterface.Mininterface.form].

Below, you find the screenshots how the program looks in various environments (graphic interface, web interface...).

from dataclasses import dataclass
from pathlib import Path
from mininterface import run

@dataclass
class Env:
  my_file: Path  # This is my help text
  my_flag: bool = False
  my_number: int = 4

if __name__ == "__main__":
    # Here, the user will be prompted
    # for missing parameters (`my_file`) automatically
    with run(Env) as m:

      # You can lean on the typing
      # Ex. directly read from the file object:
      print("The file contents:", m.env.my_file.read_text())

      # You can use various dialog methods,
      # like `confirm` for bool
      if m.confirm("Do you want to continue?"):

        # or `select` for choosing a value
        fruit = m.select(("apple", "banana", "sirup"), "Choose a fruit")

        if fruit == "apple":
          # or `form` for an arbitrary values
          m.form({
            "How many": 0,
            "Choose another file": m.env.my_file
          })

Launch with ./program.py:

Tutorial Tutorial Tutorial Tutorial

Or at the remote machine MININTERFACE_INTERFACE=tui ./program.py:

Tutorial Tutorial Tutorial Tutorial

Or via the plain text MININTERFACE_INTERFACE=text ./program.py:

Tutorial

Or via web browser MININTERFACE_INTERFACE=web ./program.py:

Tutorial

You can always set Env via CLI or a config file:

$ ./program.py --help
usage: program.py [-h] [OPTIONS]

╭─ options ──────────────────────────────────────────────────────────────╮
│ -h, --help             show this help message and exit                 │
│ -v, --verbose          Verbosity level. Can be used twice to increase. │
│ --my-file PATH         This is my help text (required)                 │
│ --my-flag, --no-my-flag                                                │
│                        (default: False)                                │
│ --my-number INT        (default: 4)                                    │
╰────────────────────────────────────────────────────────────────────────╯

Goodbye argparse world

You want to try out the Mininterface with your current ArgumentParser?

You're using positional arguments, subparsers, types in the ArgumentParser... Mininterface will give you immediate benefit. Just wrap it inside the [run][mininterface.run] method.

#!/usr/bin/env python3
from argparse import ArgumentParser
from datetime import time
from pathlib import Path

from mininterface import run

parser = ArgumentParser()
subparsers = parser.add_subparsers(dest="command", required=True)
sub1 = subparsers.add_parser("build", help="Build something.")
sub1.add_argument("--optimize", action="store_true", help="Enable optimizations.")
parser.add_argument("input_file", type=Path, help="Path to the input file.")
parser.add_argument("--time", type=time, help="Given time")

# Old version
# env = parser.parse_args()
# env.input_file  # a Path object

# New version
m = run(parser)
m.env.input_file  # a Path object

# Live edit of the fields
m.form()

Now, the help text looks much better. Try it in the terminal to see the colours.

$ ./program.py --help
usage: program.py [-h] [OPTIONS] PATH

╭─ positional arguments ──────────────────────────────────────────────────╮
│ PATH                    Path to the input file. (required)              │
╰─────────────────────────────────────────────────────────────────────────╯
╭─ options ───────────────────────────────────────────────────────────────╮
│ -h, --help              show this help message and exit                 │
│ -v, --verbose           Verbosity level. Can be used twice to increase. │
│ --time HH:MM[:SS[…]]    Given time (default: 00:00:00)                  │
╰─────────────────────────────────────────────────────────────────────────╯
╭─ build options ─────────────────────────────────────────────────────────╮
│ --build.optimize, --build.no-optimize                                   │
│                         Enable optimizations. (default: False)          │
╰─────────────────────────────────────────────────────────────────────────╯

And what happens when you launch the program? First, Mininterface asks you to provide the missing required arguments. Note the button to raise a file picker dialog.

Positional fields

Then, a .form() call will create a dialog with all the fields.

Whole form

You will access the arguments through [m.env][mininterface.Mininterface.env]

print(m.env.time)  # -> 14:21

If you're sure enough to start using Mininterface, convert the argparse into a dataclass. Then, the IDE will auto-complete the hints as you type.

!!! warning The argparse support is considered mostly for your evaluation as there are some differences for advanced argparse CLI interfaces.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mininterface-1.1.2.tar.gz (114.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mininterface-1.1.2-py3-none-any.whl (145.3 kB view details)

Uploaded Python 3

File details

Details for the file mininterface-1.1.2.tar.gz.

File metadata

  • Download URL: mininterface-1.1.2.tar.gz
  • Upload date:
  • Size: 114.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for mininterface-1.1.2.tar.gz
Algorithm Hash digest
SHA256 88ce2f178e492ac57c0acb94a68f3c0ba78b76c01e34720bfacfe7e856fa4e03
MD5 f9001190dbdc669b4a3f4726812cb213
BLAKE2b-256 25bbd2e10c117c6a11b4ead5d38a703accd48e703ef5a2196f5430d4704662b8

See more details on using hashes here.

File details

Details for the file mininterface-1.1.2-py3-none-any.whl.

File metadata

  • Download URL: mininterface-1.1.2-py3-none-any.whl
  • Upload date:
  • Size: 145.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for mininterface-1.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 615aaecb5228f84737a96a3044b4011091f9c82ac3a0871b872f10b897555b2f
MD5 dd306c6971f4d2664ed8b78e94526a75
BLAKE2b-256 2d10fcb7220167112f2107cb205a7f94e022eefd257b60dd0c5f61f11a9b5018

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page