Skip to main content

A minimal access to GUI, TUI, CLI and config

Project description

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

License: GPL v3 Build Status

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 that displays such window or its textual fallback.

from dataclasses import dataclass
from mininterface import run

@dataclass
class Config:
    """Set of options."""
    test: bool = False
    """My testing flag"""
    important_number: int = 4
    """This number is very important"""

if __name__ == "__main__":
    args: Config = run(Config, prog="My application").get_args()
    print(args.important_number)    # suggested by the IDE with the hint text "This number is very important"

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

$ ./hello.py
usage: My application [-h] [--test | --no-test] [--important-number INT]

Set of options.

╭─ options ──────────────────────────────────────────────────────────╮
│ -h, --help              show this help message and exit            │
│ --test, --no-test       My testing flag (default: False)           │
│ --important-number INT  This number is very important (default: 4) │
╰────────────────────────────────────────────────────────────────────╯

You get several useful methods to handle user dialogues. Here we bound the interface to a with statement that redirects stdout directly to the window.

with run(Config) as m:
    print(f"Your important number is {m}")
    boolean = m.is_yes("Is that alright?")

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

Loading config file is a piece of cake. Alongside program.py, put program.yaml and put there some of the arguments. Instantly loaded.

important_number: 555

Background

Wrapper between the tyro argparse replacement and tkinter_form that converts dicts into a GUI.

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 --test causes args.test be set to True.
  • The main benefit: Launch it without parameters as program.py to get a full working window with all the flags ready to be edited.
  • Running on a remote machine? Automatic regression to the text interface.

Installation

Install with a single command from PyPi.

pip install mininterface

Docs

You can easily nest the configuration. (See also Tyro Hierarchical Configs).

Just put another dataclass inside the config file:

@dataclass
class FurtherConfig:
    token: str
    host: str = "example.org"

@dataclass
class Config:
    further: FurtherConfig

...
print(config.further.host)  # example.org

A subset might be defaulted in YAML:

further:
  host: example.com

Or by CLI:

$./program.py --further.host example.net

mininterface

run(config=None, interface=GuiInterface, **kwargs)

Wrap your configuration dataclass into run to access the interface. Normally, an interface is chosen automatically. We prefer the graphical one, regressed to a text interface on a machine without display. Besides, if given a configuration dataclass, the function enriches it with the CLI commands and possibly with the default from a config file if such exists. It searches the config file in the current working directory, with the program name ending on .yaml, ex: program.py will fetch ./program.yaml.

  • config:ConfigClass: Dataclass with the configuration.
  • interface: Which interface to prefer. By default, we use the GUI, the fallback is the REPL.
  • **kwargs: The same as for argparse.ArgumentParser.
  • Returns: interface Interface used.

You cay context manage the function by a with statement. The stdout will be redirected to the interface (GUI window).

See the initial examples.

Interfaces

Several interfaces exist:

  • Mininterface – The base interface. Does not require any user input and hence is suitable for headless testing.
  • GuiInterface – A tkinter window.
  • TuiInterface – An interactive terminal.
    • TextualInterface – If textual installed, rich interface is used.
    • TextInterface – Plain text only interface with no dependency as a fallback.
  • ReplInterface – A debug terminal. Invokes a breakpoint after every dialog.

You can invoke one directly instead of using mininterface.run. Then, you can connect a configuration object to the CLI and config file with parse_args if needed.

with TuiInterface("My program") as m:
    number = m.ask_number("Returns number")

Mininterface(title: str = '')

Initialize.

alert(self, text: str)

Prompt the user to confirm the text.

ask(self, text: str) -> str

Prompt the user to input a text.

ask_args(self) -> ~ConfigInstance

Allow the user to edit whole configuration. (Previously fetched from CLI and config file by parse_args.)

ask_form(self, args: FormDict, title="") -> dict

Prompt the user to fill up whole form.

  • args: Dict of {labels: default value}. The form widget infers from the default value type. The dict can be nested, it can contain a subgroup. The default value might be mininterface.FormField that allows you to add descriptions. A checkbox example: {"my label": FormField(True, "my description")}
  • title: Optional form title.

ask_number(self, text: str) -> int

Prompt the user to input a number. Empty input = 0.

get_args(self, ask_on_empty_cli=True) -> ~ConfigInstance

Returns whole configuration (previously fetched from CLI and config file by parse_args). If program was launched with no arguments (empty CLI), invokes self.ask_args() to edit the fields.

is_no(self, text: str) -> bool

Display confirm box, focusing no.

is_yes(self, text: str) -> bool

Display confirm box, focusing yes.

m = run(prog="My program")
print(m.ask_yes("Is it true?"))  # True/False

parse_args(self, config: Callable[..., ~ConfigInstance], config_file: pathlib.Path | None = None, **kwargs) -> ~ConfigInstance

Parse CLI arguments, possibly merged from a config file.

  • config: Dataclass with the configuration.
  • config_file: File to load YAML to be merged with the configuration. You do not have to re-define all the settings, you can choose a few.
  • **kwargs The same as for argparse.ArgumentParser.
  • Returns: ConfigInstance Configuration namespace.

Standalone

When invoked directly, it creates simple GUI dialogs.

$ mininterface  --help
usage: Mininterface [-h] [OPTIONS]

Simple GUI dialog. Outputs the value the user entered.

╭─ options ─────────────────────────────────────────────────────────────────────────────────╮
│ -h, --help              show this help message and exit                                   │
│ --alert STR             Display the OK dialog with text. (default: '')                    │
│ --ask STR               Prompt the user to input a text. (default: '')                    │
│ --ask-number STR        Prompt the user to input a number. Empty input = 0. (default: '') │
│ --is-yes STR            Display confirm box, focusing yes. (default: '')                  │
│ --is-no STR             Display confirm box, focusing no. (default: '')                   │
╰───────────────────────────────────────────────────────────────────────────────────────────╯

You can fetch a value to i.e. a bash script.

$ mininterface  --ask-number "What's your age?"  # GUI window invoked
18

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-0.4.3.tar.gz (18.8 kB view details)

Uploaded Source

Built Distribution

mininterface-0.4.3-py3-none-any.whl (20.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: mininterface-0.4.3.tar.gz
  • Upload date:
  • Size: 18.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.9

File hashes

Hashes for mininterface-0.4.3.tar.gz
Algorithm Hash digest
SHA256 c9e350f365a64b20f26cd97a93aeda2e974c9974064c5785df88275bc9a4d8fc
MD5 ee4f1f6f670eae25b9383ff11b963712
BLAKE2b-256 70a2e9094fb9c47b8f3e5567bee958eead5732289ce8ba1ca85eca1dad4487fd

See more details on using hashes here.

File details

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

File metadata

  • Download URL: mininterface-0.4.3-py3-none-any.whl
  • Upload date:
  • Size: 20.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.9

File hashes

Hashes for mininterface-0.4.3-py3-none-any.whl
Algorithm Hash digest
SHA256 6918094f2c26f59c06be66ac0d3514767007269e814b6784bccfc09a29d7e250
MD5 666ba28eaf16ee30bc50a285aa41bbd7
BLAKE2b-256 9a6e9d88f23774d3d7762433de2673eb70c944cf993077874fc0484fe75c22ae

See more details on using hashes here.

Supported by

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