Skip to content
/ Badges Public

Tiny, dependency-light helpers for beautiful terminal output, interactive prompts, a less-style pager, structured tables, and a cute ASCII world map. Designed to drop straight into scripts and CLIs.

License

Notifications You must be signed in to change notification settings

EntySec/Badges

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

98 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Badges

Developer Language Forks Stars CodeFactor

Tiny, dependency-light helpers for beautiful terminal output, interactive prompts, a less-style pager, structured tables, and a cute ASCII world map. Designed to drop straight into scripts and CLIs.


Features

  • Pretty status lines: [*], [+], [-], [!], [i] with color and bold.
  • Interactive input with history and ANSI prompts (prompt_toolkit).
  • Built-in pager (less-like) for long output (Enter / Space / a / q).
  • Logging of all output and prompts to a file (opt-in).
  • Tables: quick, readable ASCII tables.
  • ASCII World Map: plot a dot by latitude/longitude.
  • Command wrapper: utilities for building interactive shells.

Installation

Note: This project is typically installed from source/git.

pip install git+https://github.com/EntySec/Badges

Quick Start

from badges import Badges

ui = Badges()

# Optional: configure once per process
ui.set_less(True)                      # enable less-like paging
ui.set_log("mytool.log")               # log all prints & prompts
ui.set_history(".mytool_history")      # persistent input history

ui.print_process("Starting...")
ui.print_success("All good.")
ui.print_warning("Heads up.")
ui.print_error("Something went wrong.")
ui.print_information("FYI only.")

answer = ui.input_question("Proceed? [y/N]: ")
if answer.lower() in ("y", "yes"):
    ui.print_process("Continuing...")
else:
    ui.print_warning("Aborted by user.")

API Overview

The package exposes four main entry points:

from badges import Badges, Tables, Map

1) Badges (printing & input)

Badges extends the IO class (see below). It provides convenience prefixed prints and inputs:

Printing

  • print_empty(message, *, start='%remove%end', end='%newline', time=False, log=None, less=None)
  • print_usage(message, start='%remove', ...)Usage: ...
  • print_process(message, start='%remove', ...)%bold%blue[*]%end prefix
  • print_success(message, start='%remove', ...)%bold%green[+]%end
  • print_error(message, start='%remove', ...)%bold%red[-]%end
  • print_warning(message, start='%remove', ...)%bold%yellow[!]%end
  • print_information(message, start='%remove', ...)%bold%white[i]%end

Where start/end accept ColorScript tokens. Common tokens include:

  • %bold, %red, %green, %blue, %yellow, %white
  • %end (reset styles), %newline (append newline), %remove (clear line), %clear (clear screen), %line (underline)

The underlying render call is IO.print(message, start, end, time, log, less).

Input

  • input_empty(message='', start='%end', end='', **ptk_kwargs) -> str
  • input_question(message, start='%end', ...) -> str%bold%white[?]%end prompt
  • input_arrow(message, start='%end', ...) -> str%bold%white[>]%end prompt

Input uses a single PromptSession with optional history (set_history(path)).

Global configuration (module-global state)

  • set_log(path: str) – when set, every print and prompt is appended to path.
  • set_history(path: str) – enables prompt_toolkit.FileHistory(path) for inputs.
  • set_less(enabled: bool) – turns the pager on/off globally (default: True if unset).

You can temporarily override per call via log= or less= parameters to print().

Examples

Timestamped messages:

ui.print_process("Connecting...", time=True)  # [*] 14:32:10 - Connecting...

Disable pager for a single long line:

ui.print_information(big_text, less=False)

Sensitive input (avoid logging this one):

ui.set_log("app.log")
secret = ui.input_question("Enter API key: ", log=False)

2) IO (base class used by Badges)

Core lower-level I/O utilities:

  • print(message='', start='%remove%end', end='%newline', time=False, log: Optional[bool]=None, less: Optional[bool]=None) -> None Renders start + message + end via ColorScript and prints via:

    • Pager (print_less) when less is True.
    • Direct stdout otherwise. If log is enabled (globally or via arg), writes the rendered string to file.
  • input(message='', start='%end', end='', **kwargs) -> str Builds the prompt (with ANSI) and returns the user’s input. If log is enabled, logs the prompt and the typed response.

  • set_log(path), set_history(path), set_less(bool) – global setters described above.

  • print_less(data: str) A simple pager:

    • Shows (rows - 3) lines per “screen”.
    • Controls: Enter (advance one line), Space (+10 lines), a (show all), q (quit).
  • suppress_function(fn, *a, **kw) -> Any Run a function while suppressing its stdout/stderr.

  • print_function(fn, *a, **kw) -> Any Run a function, capture its stdout/stderr, then print the captured output (through the pager).

Tip: In CI/non-TTY environments the pager may wait for a keypress. Disable it with set_less(False) or pass less=False on prints.


3) Tables (quick ASCII tables)

from badges import Tables

tbl = Tables()
rows = [
    ("111", "Ivan Nikolskiy"),
    ("112", "Jane Doe"),
]
tbl.print_table("Users", ("ID", "Name"), *rows)

Sample output:

Users:

    ID      Name
    --      ----
    111     Ivan Nikolskiy
    112     Jane Doe

Notes

  • The implementation is deliberately simple and favors readability over speed.
  • It handles ANSI sequences by adjusting width so colored cells align.
  • Optional extra_fill= kwarg sets padding per column (default 4).

4) Map (ASCII world map)

from badges import Map

m = Map()                       # 'world' map, red dot by default
m.deploy(55.751244, 37.618423)  # Moscow
print(m.get_map())

You’ll get a world ASCII map with a colored dot marking the point. Constructor options:

  • Map(map_name='world', dot='%red*%end')

Helpers:

  • location(latitude, longitude) -> (x, y)
  • deploy(latitude, longitude) -> None
  • get_map() -> str

Building an Interactive Shell

badges/cmd.py provides a higher-level scaffold (Cmd) for CLI shells with:

  • Intro and customizable prompt (ColorScript aware).
  • Command discovery (internal do_<name> methods and external command modules).
  • Shortcuts (aliases), autocompletion, history, ! system-command passthrough, etc.

Minimal sketch:

from badges.cmd import Cmd, Command

class Hello(Cmd):
    def do_hello(self, args):
        """Say hello."""
        self.print_success("Hello!")

if __name__ == "__main__":
    shell = Hello(prompt='%green$ %end', intro='%bold%lineDemo%end')
    shell.loop()

See badges/cmd.py for the full capabilities: external command loading, verify_command, argument parsing utilities, and built-ins like help, clear, exit, source, ! (system).


Patterns & Recipes

Capture noisy function output

ui = Badges()

def noisy():
    print("stdout noise")
    import sys
    print("stderr noise", file=sys.stderr)
    return 42

result = ui.suppress_function(noisy)  # prints nothing, returns 42
ui.print_information("Now showing captured output:")
ui.print_function(noisy)              # prints via pager

Make paging optional (TTY-aware)

import sys
ui = Badges()
ui.set_less(sys.stdout.isatty())

Separate log for audit

ui = Badges()
ui.set_log("audit.log")
ui.print_process("Starting up", time=True)
name = ui.input_question("Name: ")

FAQ

Q: Why do my logs contain escape sequences? A: The library writes the rendered line (with ANSI codes) to the log file. Some viewers will show them literally; others will colorize. If you need plain text logs, strip ANSI codes yourself.

Q: Can I disable logging for a specific prompt or print? A: Yes. Pass log=False into print() or input() calls.

Q: The pager is blocking in my CI. A: Disable it globally with set_less(False) or per call with less=False.

Q: Are Badges objects thread-safe? A: No. They share module-global state (log, history, less, and a singleton PromptSession). Keep I/O on the main thread or add your own synchronization.


Contributing

  • Keep APIs small and predictable.
  • Mind cross-platform behavior of getch and terminal sizes.
  • PRs for table formatting and pager ergonomics are welcome.

About

Tiny, dependency-light helpers for beautiful terminal output, interactive prompts, a less-style pager, structured tables, and a cute ASCII world map. Designed to drop straight into scripts and CLIs.

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

Packages

No packages published

Languages