Overview •
Why use masked-input? •
Features •
Prerequisites •
Installation •
Usage •
API Reference •
Parameters •
Return Value •
Exceptions •
Implementation Details •
Notes •
Known Issues and Limitations •
Examples •
Credits & Inspiration •
License •
Star History
The masked-input function provides a secure way to read passwords or other sensitive input from the command line with customizable masking. It works across different operating systems and handles various edge cases.
Unlike getpass, masked-input provides visual feedback through masking, improving UX during password entry, especially in CLI tools. It also offers full customization and graceful fallback behavior.
- 🌐 Cross-platform compatibility - Works on Windows and POSIX-based systems
- 🎭 Customizable masking character - Define your own character to mask input (like *, •, or nothing at all)
- 🔢 Adjustable mask repeat count - Control how many masking characters appear per typed character, from single to multiple symbols, or even none
- ⌫ Proper handling of backspace and special keys - Properly deletes characters and gracefully skips over arrow keys, escape sequences, and other exotic key combos without breaking the mask flow
- ⏱️ Per-character delay - Optionally pauses after each typed character
- ⌛ Global input timeout - Abort password input after a defined total duration and optionally show a custom message when time runs out
- 🔐 Character limit - Define a maximum password length
- 🧭 Selectable input mode - Choose between:
- standard: masks each char normally
- last-char-temporary: briefly shows the last char before masking
- invisible: shows nothing at all
- pixel-lock: masks then deletes instantly
- 🧪 Fallback to standard
getpasswhen necessary - Automatically switches togetpasswhen masking isn’t feasible - ✍️ Clear and concise docstrings - Parameters documented with no fluff, easy to read and maintain
- ✅ Built-in unit tests - Comes with a robust suite of unit tests covering key usage scenarios to ensure reliability
- Python 3.9 or higher
- No external dependencies (uses only standard library modules)
- Terminal or command-line environment that supports interactive input
- On Windows: A terminal that supports ANSI escape sequences for best results
- On POSIX: Terminal with standard TTY capabilities
pip install masked-inputClone the repository or download the source code, then navigate to the project directory:
git clone https://github.com/ree-verse/masked-input.git
cd path/to/your/folder
pip install .from masked_input import masked_input
# Basic usage with default settings
password = masked_input() # Displays "Password: " with "•" masking
# Custom prompt, mask character, and mask repeat count
password = masked_input(
prompt="Enter secret key: ",
mask="*",
mask_repeat=2
)
# Hide input completely (no masking character)
password = masked_input(mask="")masked_input(
prompt: str = 'Password: ',
mask: str = '•',
mask_repeat: int = 1,
char_timeout: Optional[Union[int, float]] = None,
timeout: Optional[Union[int, float]] = None,
timeout_prompt: Optional[str] = None,
char_limit: Optional[int] = None,
mode: Literal['standard', 'last-char-temporary', 'invisible', 'pixel-lock'] = 'standard',
last_char_visible_duration: Union[int, float] = 0.1
) -> str| Parameter | Type | Default | Description |
|---|---|---|---|
prompt |
str |
'Password: ' |
The text displayed to prompt the user for input |
mask |
str |
'•' |
Character used to mask each input character (use empty string to hide completely) |
mask_repeat |
int |
1 |
Number of mask symbols displayed per each input character (1-100) |
char_timeout |
int, float, None |
None |
Delay in seconds after each character input |
timeout |
int, float, None |
None |
Total timeout in seconds for the whole input |
timeout_prompt |
str, None |
None |
Message displayed on timeout; requires timeout to be set |
char_limit |
int, None |
None |
Maximum number of input characters allowed |
mode |
str |
'standard' |
Input display mode with various options [^*] |
last_char_visible_duration |
int, float |
0.1 |
Duration in seconds the last typed character is visible (only for last-char-temporary) |
[^*]
'standard': Shows mask character for each typed character'last-char-temporary': Briefly shows each character before masking it'invisible': No visual feedback (no mask, no cursor movement)'pixel-lock': No cursor movement to prevent revealing input length
The function returns a string containing the user's input without the masking.
-
TypeError:- Raised:
- If
promptormaskare not strings - If
mask_repeatis not an integer - If
char_timeout,timeout, orlast_char_visible_durationare not int or float - If
timeout_promptis not a string - If
char_limitis not an integer - If
modeis not a string
- If
- Raised:
-
ValueError:- Raised:
- If
maskcontains more than one character - If
maskis an empty string butmodeis notinvisible - If
maskis not one of''or'•'when mode isinvisible - If
mask_repeatis not between 1 and 100 - If
timeout_promptis provided without settingtimeout - If
timeout_promptis an empty string - If
char_limitis set but not positive - If
modeis not one of:standard,last-char-temporary,invisible,pixel-lock - If
modeisinvisibleormaskis empty andmask_repeat,char_timeout, orlast_char_visible_durationare set to non-default values - If
last_char_visible_durationis set whilemodeis notlast-char-temporary - If
last_char_visible_durationis not greater than zero
- If
- Raised:
-
KeyboardInterrupt:- Raised:
- If the user interrupts input (e.g., by pressing Ctrl+C)
- Raised:
- On Windows systems, the function uses the
msvcrtmodule to read characters - On POSIX-based systems, it uses
termiosandttyto set the terminal to raw mode - Falls back to
getpasswhen the script is not run in an interactive terminal
- Special keys (arrows, function keys, etc.) are properly handled and ignored
- The function correctly processes backspace to remove the last character
- Only printable characters are added to the password
- The terminal is restored to its original state even if an exception occurs
- The
mask_repeatparameter must be an integer between 1 and 100 to avoid overflow errors or memory issues during mask repetition. Values outside this range may raise anOverflowErrororMemoryError
- Windows Character Input: On Windows systems, certain characters like "à" and other accented characters require pressing the key twice to be registered correctly. This is due to how the Windows console handles special characters.
- Very long passwords may cause display issues in terminals with limited width. This does not affect password entry itself, only its visual representation.
- On Windows and POSIX,
Ctrl+MandCtrl+Jsend the same sequences asEnter(\r) andLine Feed(\n), so they behave like pressing Enter. Similarly,Ctrl+Hsends the same sequence as Backspace (\b), which deletes a character. Sincemasked-inputfocuses on handling individual key inputs (not complex shortcuts), these overlaps are expected and not treated specially just like ingetpassand Python’s standardinput. - Input with non-standard keyboard layouts may have unexpected behavior on some platforms.
- Some terminal emulators may not properly handle the masking behavior, especially when using uncommon terminal settings.
- No error is raised if
last_char_visible_durationis set while mode isn’tlast-char-temporary, as long as its value remains at 0.1 (the default).
# Standard masking:
password = masked_input(prompt="Enter password: ", mask="*")
# Temporarily showing each character before masking:
password = masked_input(
prompt="Enter password: ",
mask="*",
mode="last-char-temporary",
last_char_visible_duration=0.2
)
# Invisible input (no visual feedback):
password = masked_input(mode="invisible")
# Input with timeout:
password = masked_input(
timeout=30,
timeout_prompt="Input timed out!"
)
# Character limit:
password = masked_input(char_limit=12)
# Delay between each character input (slows down rendering intentionally):
password = masked_input(
prompt="Password: ",
char_timeout=0.3
)
# Mask repeated for each character (e.g., "**" instead of "*"):
password = masked_input(
mask ="*",
mask_repeat=2
)# Example usage:
password = masked_input(prompt='Enter your password: ', mask='*', mask_repeat=2)
print(f'Your password is: {password}')This project was inspired by pwinput, which provided the initial idea and implementation of cross-platform masked input in Python.
Big respect to Al Sweigart for his contributions to the open-source ecosystem.
Released under the MIT License © 2025 Ree-verse.
Disclaimer: This program may contain bugs. It has only been tested on AZERTY keyboards and may not function correctly on QWERTY layouts. If you encounter any issues, please open an issue to report them.