Registry / observability / manhole

manhole

JSON →
library1.8.1pypypi✓ verified 24d ago

Manhole is an in-process Python service that accepts Unix domain socket connections to provide stack traces for all threads and an interactive Python prompt. It can operate as a daemon thread or a signal handler. It is inspired by Twisted's manhole and focuses on simplicity with no external dependencies. The current version is 1.8.1, and releases appear to be on a somewhat irregular, feature-driven cadence.

pip install manhole
INSTALL
IMPORT
SIG · MANHOLE
M
manhole
observabilitypythonv1.8.1
Install
1.6s avg
Import
61ms
Disk
16MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v1.8.1 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.95 runs
installs and imports cleanly · install 0.0s · import 0.058s · 17.9MB
glibc
py 3.103.95 runs
installs and imports cleanly · install 1.6s · import 0.064s · 18MB
16MB installed
● package 16MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

install
import manhole manhole.install()
The primary way to activate the manhole in your application.
handle_connection_repl
from manhole import handle_connection_repl
One of the provided connection handlers, offering a full REPL experience.
handle_connection_exec
from manhole import handle_connection_exec
An alternative connection handler, providing a simpler 'exec' environment without full REPL features.

This quickstart demonstrates how to install `manhole` in a Python application and then connect to it using the `manhole-cli` tool. The application will print a message indicating the socket path, run in the background, and then `manhole-cli` will be used to establish an interactive session. Inside the manhole, you can inspect variables or execute code. For a richer interactive experience (history, editing), `socat readline unix-connect:/tmp/manhole-PID` is recommended instead of `manhole-cli`.

import manhole import time import os import sys def main(): print(f"Manhole will listen on /tmp/manhole-{os.getpid()}\n") manhole.install(sigmask=["USR1"], verbose=True) # Install manhole with default settings print("Manhole installed. Waiting for connection...") # Simulate a running application i = 0 while True: print(f"App running... {i}") time.sleep(2) i += 1 if i == 5: # Optionally demonstrate manual activation/deactivation print("Sending USR1 to self to potentially activate/deactivate manhole if configured as 'activate_on'") try: os.kill(os.getpid(), 10) # SIGUSR1 except AttributeError: print("SIGUSR1 not available on this OS, skipping manual signal.") if __name__ == '__main__': import subprocess # Start the application with manhole installed app_process = subprocess.Popen([sys.executable, __file__]) time.sleep(3) # Connect to the manhole using manhole-cli print(f"\nConnecting to manhole-cli for PID: {app_process.pid}...") try: # The `manhole-cli` attempts to connect to /tmp/manhole-<PID> # Note: 'socat readline' provides a better interactive experience. # 'manhole-cli' is simpler for demonstration. subprocess.run(['manhole-cli', str(app_process.pid)], check=True) except FileNotFoundError: print("manhole-cli not found. Please ensure it's installed and in your PATH.") except subprocess.CalledProcessError as e: print(f"manhole-cli failed: {e}") finally: app_process.terminate() app_process.wait() print("\nApplication terminated.")
manhole --version
Debug
Known issues
breakingSupport for Python 2.6, 3.3, and 3.4 was dropped in v1.6.0. Applications running on these older Python versions will require an older `manhole` release (e.g., <1.6.0).
fix
Upgrade to Python >=3.8 or pin `manhole` to a compatible version like `manhole<1.6.0`.
affects: <1.6.0
gotchaPrevious versions (before v1.7.0) had a memory leak due to `sys.last_type`, `sys.last_value`, and `sys.last_traceback` not being cleared properly, and could also suffer from double-close bugs in stream handling.
fix
Upgrade to `manhole` v1.7.0 or newer to benefit from the memory leak and double-close bug fixes.
affects: <1.7.0
gotchaWhen `socket.setdefaulttimeout()` is used in your application, older `manhole` versions (before v1.6.0) might exhibit unexpected behavior. This was fixed in v1.6.0.
fix
Upgrade to `manhole` v1.6.0 or newer to ensure correct handling when `socket.setdefaulttimeout()` is in use.
affects: <1.6.0
gotcha`manhole-cli` in versions prior to v1.7.0 was more strict about PID argument parsing, primarily expecting paths prefixed with `/tmp`. This was loosened in v1.7.0 to allow paths with any prefix.
fix
Upgrade to `manhole` v1.7.0 or newer, or ensure socket paths provided to `manhole-cli` are `/tmp`-prefixed for older versions.
affects: <1.7.0
gotchaBy default, calling `manhole.install()` multiple times will raise an `AlreadyInstalled` exception. This is part of 'strict' mode.
fix
If re-installation or multiple calls are intended, set `strict=False` in `manhole.install(strict=False)` or use the `reinstall_delay` option. An existing manhole can also be uninstalled before reinstalling.
affects: All versions
gotchaIntegrating `manhole` with uWSGI requires special configuration because uWSGI overrides signal handling. The recommended approach involves using uWSGI's internal signals or a file-based PID mechanism.
fix
Refer to the `manhole` documentation's 'Using Manhole with uWSGI' section for specific setup instructions, often involving `oneshot_on` or `activate_on` options with uWSGI signals.
affects: All versions
gotchaManhole can also be installed via the `PYTHONMANHOLE` environment variable. If set, Manhole might be automatically activated, potentially conflicting with explicit `manhole.install()` calls or altering expected behavior.
fix
Be aware of the `PYTHONMANHOLE` environment variable if your application exhibits unexpected manhole behavior. Ensure it's not set unintentionally or use it deliberately for deployment scenarios.
affects: All versions
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'manhole'
The 'manhole' package is not installed in the Python environment where the code is being run, or it's not accessible via the Python path.
fix
Install the package using pip: `pip install manhole` or ensure your virtual environment is activated if you installed it there.
ConnectionRefusedError: [Errno 111] Connection refused
This error occurs when the `manhole-cli` client tries to connect to the Unix domain socket, but the `manhole` server is not running in the target process, the socket file does not exist, or a firewall/permissions issue is blocking the connection.
fix
Ensure `manhole.install()` has been called in the target Python application to start the manhole server. Verify the `socket_path` is correct and that the process running `manhole-cli` has permission to access it. Check for stray socket files in `/tmp` and remove them if the application crashed. For remote connections, ensure the path and permissions are correctly set.
Permission denied: '/tmp/manhole-<pid>' (or a specific socket_path)
The Python process attempting to create or access the Unix domain socket file does not have the necessary write/read permissions for the specified directory (often `/tmp` by default) or the socket file itself.
fix
Ensure the user running the Python application has write permissions to the directory where the socket file is created (e.g., `/tmp`). Alternatively, specify a `socket_path` in `manhole.install(socket_path='/path/to/writable/dir/mysocket')` to a directory where the user has appropriate permissions.
IOError creating manhole trigger '%r'
This error typically occurs when `manhole` is configured to use a signal handler for activation (e.g., in uWSGI environments), and there's an issue creating the necessary trigger file or handling signals.
fix
For uWSGI, follow the specific integration instructions in the `manhole` documentation to use uWSGI signals and file monitoring, as uWSGI overrides standard signal handling. Ensure the `stack_dump_file` path is writable by the uWSGI worker process.
AlreadyInstalled: 'Manhole already installed, use strict=False to reinstall.'
By default, `manhole.install()` raises an `AlreadyInstalled` exception if called more than once in the same Python process. This can happen during application reloads or in complex process lifecycles.
fix
If you intend to reinstall or allow multiple installations, call `manhole.install(strict=False)`. If multiple installations are unintentional, debug your application startup to ensure `manhole.install()` is only called once.
Upgrade
Version history
1.8.1latest on PyPI · released Jul 4, 2024
Audit
Dependencies
pythonrequiredMinimum required Python version for the library.
Agent activity
13 hits · last 30 days
node
10
OpenAI (training)
2
Resources
manhole — pip install manhole · libregistry