Skip to main content

mukimov

A small cross-platform Python library with masked password input, terminal colors, Markdown and typed environment settings.

PyPI version Python versions License: MIT Platform

Developed by Mukimov Studio

  • ⭐ Hidden password input with stars()
  • 🎨 12 terminal colors with mukimov.color
  • 📝 Terminal Markdown rendering with mukimov.text.markdown
  • ⚙️ Typed environment settings and explicit .env loading with mukimov.env (since 0.1.8)

What is mukimov?

mukimov lets you read a password or any other secret text in the terminal while showing a mask character instead of the real keystrokes.

For example, the user really types:

123456

but the terminal shows:

Password: ******

And the function returns the real text "123456".

Starting with mukimov 0.1.4, the library also provides mukimov.color with 12 terminal colors — see the Colors sections below.

Starting with mukimov 0.1.6, the library also provides mukimov.text.markdown, a Markdown → ANSI terminal renderer — see the Markdown section below.

Starting with mukimov 0.1.7, the package also ships a mukimov CLI with --version and a cached self-updater — see the CLI / Updates section below.

Important: this is NOT hashing and NOT encryption. The library only visually hides input from people who may be looking at the screen. The real password is still returned to your program as a plain string.

New in 0.2.0 🎉

Typed strings and lists, integer bounds, grouped configuration checks, installation diagnostics and python -m mukimov are available in 0.2.0.

from mukimov import env

env.load(".env")
env.check(["SECRET_KEY", "DB_HOST"])
HOST = env.string("HOST", default="localhost")
ALLOWED_HOSTS = env.list("ALLOWED_HOSTS", default=[])
PORT = env.integer("PORT", default=8000, min=1, max=65535)
SECRET_KEY = env.required("SECRET_KEY")
HOST=localhost
ALLOWED_HOSTS=localhost,127.0.0.1,example.com
PORT=8000
SECRET_KEY=your-secret-key
DB_HOST=localhost
  • env.string(name, default=...) возвращает строку без изменения пробелов. Без default переменная обязательна. Значение default должно быть строкой.
  • env.list(name, default=..., separator=",") возвращает список строк. По умолчанию разделитель — запятая; пробелы вокруг элементов и пустые элементы удаляются. separator=";" задаёт другой разделитель. default должен быть списком строк; функция возвращает его копию, чтобы результат можно было менять. Значение a,, b, превращается в ["a", "b"], а ,, — в [].
  • env.integer(name, default=..., min=None, max=None) проверяет включительные границы, в том числе для значения по умолчанию. min и max — целые числа, min не может превышать max. Например, порт допускается от 1 до 65535.
  • Для строк и списков, как и раньше, default применяется только при отсутствии переменной. Настройка с пустым или пробельным значением вызывает EnvError. Значения по умолчанию "" и [] допустимы для отсутствующих настроек.
  • env.check(names) проверяет все указанные имена сразу. При успехе возвращает None; иначе вызывает EnvError, перечисляя отсутствующие или пустые имена. Повторы удаляются; пустая коллекция допустима. После env.load() ошибка также показывает имена из последнего загруженного .env. Значения не показываются. Эта функция проверяет наличие; типы проверяются соответствующими getter-функциями.

Пример объединённой ошибки:

Обязательные переменные отсутствуют или пусты:
SECRET_KEY
DB_HOST
Переменные в .env:
DB_PASS
SUPER_KEY

CLI diagnostics and module launch

mukimov doctor
python -m mukimov --version
python -m mukimov --help
python -m mukimov doctor
python -m mukimov update

doctor works offline and reports the package version, Python interpreter, platform, package and Scripts directories, dependency availability, and the launcher selected by PATH. Exit code 0 means no detected problems; 1 means missing tools or a launcher from another interpreter. It never prints environment values or reads .env, and it does not install, upgrade or change PATH.

Если mukimov не распознаётся в PowerShell, выполните python -m mukimov doctor. При отсутствии команды добавьте папку Scripts нужного Python в PATH или активируйте виртуальное окружение. Новый терминал подхватит изменения PATH. Запуск через python -m mukimov использует именно выбранный Python и не требует отдельной команды mukimov в PATH; библиотека должна быть установлена в этом Python.

Installation

pip install mukimov

Upgrade to the latest version:

pip install --upgrade mukimov

Or with the built-in updater (uses the same Python/pip that runs mukimov):

mukimov update

Check the installed version:

mukimov --version
pip show mukimov

Quick Start

The simplest possible example:

from mukimov import stars

password = stars("Password: ")

What the user sees:

Password: ******

If the user typed 123456, the variable password contains:

"123456"

Custom Mask ✨

The second argument controls which character is shown for every typed symbol:

stars("Password: ", "*")  # Password: ******
stars("Password: ", "/")  # Password: //////
stars("Password: ", "#")  # Password: ######
stars("Password: ", "•")  # Password: ••••••

API:

stars(prompt, mask="*")
Parameter Type Description
prompt str Text displayed before input.
mask str Character shown instead of each typed symbol. Defaults to "*".

Important: mask must contain exactly ONE character.

Full Example

A realistic login prompt:

from mukimov import stars

username = input("Username: ")
password = stars("Password: ")

print(f"Welcome, {username}!")

Example terminal session:

Username: Mukimov
Password: ********
Welcome, Mukimov!

Note that the real password is never printed — only the mask is shown.

Colors 🎨

Available since mukimov 0.1.4.

mukimov.color provides 12 terminal colors for your CLI output.

Установка актуальной версии:

pip install -U mukimov

Простой пример:

from mukimov.color import red, green, blue

print(red("Error"))
print(green("Success"))
print(blue("Information"))

red(), green() и остальные функции НЕ вызывают print() самостоятельно. Они возвращают ANSI-цветную строку, которую можно передавать в print(), input(), stars() и другие функции.

Пример:

message = red("Error")
print(message)

Все 12 цветов

Function Color
red() Red
green() Green
blue() Blue
yellow() Yellow
orange() Orange
purple() Purple
pink() Pink
cyan() Cyan
lime() Lime
gray() Gray
white() White
gold() Gold

Полный импорт:

from mukimov.color import (
    red,
    green,
    blue,
    yellow,
    orange,
    purple,
    pink,
    cyan,
    lime,
    gray,
    white,
    gold,
)

Colors + input()

from mukimov.color import red, green

username = input(red("Username: "))
password = input(green("Password: "))

Цвет применяется к prompt терминала: текст приглашения отображается цветным, а введённое пользователем значение остаётся обычным.

Colors + stars()

Один из главных примеров README:

from mukimov import stars
from mukimov.color import cyan, green, red

print(cyan("=== LOGIN ==="))

username = input(green("Username: "))
password = stars(green("Password: "))

if username == "Mukimov":
    print(green("Login successful!"))
else:
    print(red("Invalid username!"))

stars() продолжает скрывать ввод пароля (показывает mask-символы вместо реальных нажатий), а цветовая функция отвечает только за цвет prompt.

Validation

Функции цветов принимают только str.

Например:

red(123)

результат:

TypeError: red() expected str, got int

Также запрещены пустые строки и строки только из whitespace:

red("")
red("   ")
red("\t")
red("\n")

Ожидается:

ValueError: red() text cannot be empty

При этом:

red("Username: ")

полностью корректно.

Исходный текст сохраняется без .strip() — пробелы внутри нормального текста разрешены и не изменяются.

ANSI / RESET

Цвет реализован через ANSI escape sequences: каждая функция оборачивает текст в код своего цвета и автоматически добавляет RESET (\x1b[0m) в конец строки, поэтому цвет не распространяется на последующий вывод.

Например:

print(red("Error"))
print("Normal text")

Normal text отображается обычным цветом терминала.

Поддержка:

  • Windows Terminal
  • PowerShell
  • Linux terminals

Для цветов не требуются сторонние зависимости — только чистый Python.

Markdown 🎨

Available since mukimov 0.1.6.

mukimov.text.markdown renders Markdown as beautiful ANSI output directly in your terminal:

from mukimov.text import markdown

markdown.print("# Hello")
markdown.print("**Bold text**")
markdown.print("*Italic text*")

Two functions, two different jobs:

markdown.render(...)  # → returns `str` (prints nothing by itself)
markdown.print(...)   # → prints the rendered result to the terminal

Example:

text = markdown.render("**Hello**")
print(text)

Supported Markdown: headings H1–H6, **bold**, __bold__, *italic*, _italic_, ***bold + italic***, ~~strikethrough~~, `inline code`, > quotes, unordered lists (-, *, +), ordered lists (1.), --- rules, [links](https://...), fenced code blocks with language, and GitHub-style tables with alignment.

Tables are drawn with box characters and correct column widths (Unicode-aware, ANSI-aware):

markdown.print("""
| Name | Language |
|------|----------|
| Mukimov | Python |
| Alex | Go |
""")

Code blocks keep their content untouched (no Markdown inside is interpreted) and show the language when it is given:

markdown.print("""
```python
def hello(name):
    if name:
        print(f"Hello {name}")
```
""")

Markdown combines with mukimov.color — your color stays, Markdown styling is applied on top:

from mukimov.text import markdown
from mukimov.color import green

markdown.print(green("**Success!**"))

Success! stays green and becomes bold at the same time.

Notes:

  • Markdown parsing is done by the small, stable markdown-it-py dependency (installed automatically with mukimov); the ANSI terminal renderer itself is implemented inside mukimov.
  • Full LaTeX math support is planned for a future release: $...$ syntax currently passes through as plain text and never crashes.
  • markdown.render() / markdown.print() accept only str (otherwise TypeError) and return "" / print an empty line for an empty string.

Environment settings / .env ⚙️

Available since mukimov 0.1.8.

from mukimov import env

env.load(".env")
DEBUG = env.boolean("DEBUG", default=False)
PORT = env.integer("PORT", default=8000)
SECRET_KEY = env.required("SECRET_KEY")

Пример файла .env (это настройки, Python-код пишется в .py):

DEBUG=true
PORT=8000
SECRET_KEY=your-secret-key
  • env.load(path=".env", override=False) явно загружает UTF-8 файл относительно текущей рабочей директории. Возвращает кортеж имён переменных без значений. Системные переменные имеют приоритет; override=True разрешает заменить их. Кавычки, комментарии, export и многострочные значения поддерживаются. Подстановка ${NAME} отключена: значения сохраняются буквально. Повторное имя в одном файле получает последнее значение.
  • env.boolean(name, default=...) принимает true/false, 1/0, yes/no, on/off, без учёта регистра и окружающих пробелов.
  • env.integer(name, default=...) читает целое десятичное число, включая знак.
  • env.required(name) возвращает непустую строку без изменения её содержимого. Отсутствующее, пустое или состоящее только из пробелов значение вызывает env.EnvError (подкласс ValueError).
  • default используется только для отсутствующей переменной. Пустое или неправильное значение вызывает ошибку даже при наличии default. Без default переменная обязательна. Default должен иметь правильный тип.
  • Без env.load() функции читают только системное окружение. Импорт библиотеки сам по себе не читает .env. Отсутствующий файл вызывает FileNotFoundError.
  • Ошибка синтаксиса содержит номер строки, но не её содержимое; файл с ошибкой не загружается частично. Имена должны соответствовать [A-Za-z_][A-Za-z0-9_]*.

Если после загрузки .env в файле есть только:

DB_PASS=some-password
SUPER_KEY=some-key

и SECRET_KEY отсутствует также в системном окружении:

env.required("SECRET_KEY")

ошибка содержит только имена, без паролей и других значений:

Переменная SECRET_KEY в .env отсутствует!
Переменные в .env:
DB_PASS
SUPER_KEY

Если нужная переменная существует в системном окружении, она будет использована, даже если её нет в файле. Список в ошибке относится только к последнему успешно загруженному файлу, а не ко всем переменным компьютера. При пустом значении ошибка явно сообщает об этом. .env с секретами не следует добавлять в Git или пакет.

Для Django можно указать путь независимо от текущей директории:

from pathlib import Path
from mukimov import env

BASE_DIR = Path(__file__).resolve().parent.parent
env.load(BASE_DIR / ".env")
DEBUG = env.boolean("DEBUG", default=False)
SECRET_KEY = env.required("SECRET_KEY")

Errors

mukimov raises clear, descriptive errors in Russian. Each message tells you which parameter is wrong, what value was passed, why it is wrong, what was expected, and shows a correct example.

Wrong usage:

stars("Password: ", "//")

Error:

ValueError: Параметр mask='//' содержит 2 символа. Допускается только 1 символ.
Пример: stars("Password: ", "*")

More examples (real messages from the library):

stars("Password: ", "")
ValueError: Параметр mask='' пустой. Укажите ровно 1 символ для маскировки.
Пример: stars("Password: ", "*")
stars("Password: ", 123)
TypeError: Параметр mask должен быть строкой (str), но получен int: 123.
Пример: stars("Password: ", "*")
stars(123)
TypeError: Параметр prompt должен быть строкой (str), но получен int: 123.
Пример: stars("Password: ")

Platform Support

Only systems actually supported by the current code are listed:

OS Backend
Windows msvcrt
Linux termios / tty
macOS termios / tty

Password input and colors use only the Python standard library. Markdown uses markdown-it-py and wcwidth; .env loading uses python-dotenv. When standard input is not a TTY (pipes, IDE consoles, CI), it safely falls back to getpass with no echo.

Extra behavior worth knowing:

  • Backspace deletes the last mask character and the last symbol.
  • Enter finishes input.
  • Ctrl+C raises KeyboardInterrupt, Ctrl+D on empty input raises EOFError.

Why mukimov?

The goal of mukimov is a simple, short API for masked terminal input.

mukimov:

from mukimov import stars

password = stars("Password: ", "•")

And the standard-library alternative, where your Python version supports echo_char:

from getpass import getpass

password = getpass("Password: ", echo_char="•")

If you like the classic getpass, keep using it — mukimov is just a compact option when you want per-character masking with a tiny API.

Security 🔒

mukimov hides the password only visually, while it is being typed.

It does NOT:

  • hash the password
  • encrypt the password
  • store the password securely by itself
  • protect the process from malware
  • protect the contents of the process memory

After input, the function returns the real password as a regular Python string. To store passwords, developers must separately use a reliable password-hashing solution.

Also, error messages and logs of this library never include the typed password — only configuration values (prompt, mask) may appear in validation errors.

API

stars(prompt="Password: ", mask="*")

Parameters:

  • prompt: str — text displayed before input.
  • mask: str — exactly one character shown instead of each typed symbol.

Returns:

  • str — the real text the user typed.

Exceptions:

  • TypeError — prompt or mask is not a string.
  • ValueError — mask is empty or longer than one character.

Color API

red(text: str) -> str
green(text: str) -> str
blue(text: str) -> str
yellow(text: str) -> str
orange(text: str) -> str
purple(text: str) -> str
pink(text: str) -> str
cyan(text: str) -> str
lime(text: str) -> str
gray(text: str) -> str
white(text: str) -> str
gold(text: str) -> str

Each color function takes a string and returns it wrapped in its ANSI color code with RESET applied at the end. Raises TypeError for non-string input and ValueError for empty/whitespace-only strings.

Markdown API

from mukimov.text import markdown

markdown.render(text: str) -> str   # render Markdown to an ANSI string
markdown.print(text: str) -> None   # render and print to the terminal

render() returns the styled string without printing anything; print() writes the rendered result to the terminal. Both raise TypeError for non-string input (e.g. markdown.render() expected str, got int). LaTeX math rendering is planned for a future release.

CLI / Updates 🔄

Available since mukimov 0.1.7.

Show the installed version:

mukimov --version
mukimov 0.2.0

Check PyPI and upgrade to the latest release (no confirmation asked):

mukimov update

If a newer version exists, mukimov upgrades the current installation with the same interpreter that runs it (python -m pip install --upgrade mukimov) and prints the old and new versions:

Updated mukimov: 0.1.8 → 0.2.0

If the latest version is already installed:

Already up to date (обновление не требуется): mukimov 0.2.0

When a new release is known, other CLI invocations print a reminder to stderr (stdout stays script-friendly):

⚠ New mukimov version available: 0.2.0
Run: mukimov update

Notes:

  • The PyPI check is cached on disk for 24 hours (%LOCALAPPDATA%\mukimov on Windows, ~/.cache/mukimov elsewhere), so repeated CLI calls do not hammer PyPI.
  • Plain import mukimov never touches the network.
  • The library is never upgraded automatically — only mukimov update does.
  • Network/PyPI/pip problems print a clear error and exit with code 1 without tracebacks.

Project

Metadata

Release files for mukimov 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mukimov 0.2.0
File Size Uploaded Provenance Actions
mukimov-0.2.0.tar.gz 49.0 kB Without provenance Details for mukimov-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for mukimov 0.2.0
File Interpreter ABI Platform Actions
mukimov-0.2.0-py3-none-any.whl Python 3 none any Details for mukimov-0.2.0-py3-none-any.whl

Total release size: 79.5 kB

Release files / mukimov-0.2.0.tar.gz

Download URL mukimov-0.2.0.tar.gz
Size 49.0 kB
Tags Source
SHA-256 checksum
How to use checksums
c891eefa98866042df6e8372d19e8e1104653b54779a691b4edc0c44b4a85cbe
BLAKE2b-256 checksum
How to use checksums
ff68bac73087929823d93d6e04019efde80b7dd8f5ceb2e1becf99a4259ea350
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release files / mukimov-0.2.0-py3-none-any.whl

Download URL mukimov-0.2.0-py3-none-any.whl
Size 30.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b8fbeecf55afc0a22b23f0923182b44b5838e030fa8f87df41d3450eba25d39a
BLAKE2b-256 checksum
How to use checksums
9d508dde7eba4aa0a79a049fcd8d92aef2d6e9c8109590e2ef4543ccd55831c5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Security for mukimov 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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