========
Overview
========
Features
========
* Uses unix domain sockets, only root or same effective user can connect.
* Can run the connection in a thread or in a signal handler (see ``oneshot_on`` option).
* Can start the thread listening for connections from a signal handler (see ``activate_on`` option)
* Compatible with apps that fork, reinstalls the Manhole thread after fork - had to monkeypatch os.fork/os.forkpty for
this.
* Compatible with gevent and eventlet with some limitations - you need to either:
* Use ``oneshot_on``, *or*
* Disable thread monkeypatching (eg: ``gevent.monkey.patch_all(thread=False)``, ``eventlet.monkey_patch(thread=False)``
Note: on eventlet `you might <https://github.com/eventlet/eventlet/issues/401>`_ need to setup the hub first to prevent
circular import problems:
.. sourcecode:: python
import eventlet
eventlet.hubs.get_hub() # do this first
eventlet.monkey_patch(thread=False)
* The thread is compatible with apps that use signalfd (will mask all signals for the Manhole threads).
Options
-------
.. code-block:: python
manhole.install(
verbose=True,
verbose_destination=2,
patch_fork=True,
activate_on=None,
oneshot_on=None,
sigmask=manhole.ALL_SIGNALS,
socket_path=None,
reinstall_delay=0.5,
locals=None,
strict=True,
)
* ``verbose`` - Set it to ``False`` to squelch the logging.
* ``verbose_destination`` - Destination for verbose messages. Set it to a file descriptor or handle. Default is
unbuffered stderr (stderr ``2`` file descriptor).
* ``patch_fork`` - Set it to ``False`` if you don't want your ``os.fork`` and ``os.forkpy`` monkeypatched
* ``activate_on`` - Set to ``"USR1"``, ``"USR2"`` or some other signal name, or a number if you want the Manhole thread
to start when this signal is sent. This is desirable in case you don't want the thread active all the time.
* ``thread`` - Set to ``True`` to start the always-on ManholeThread. Default: ``True``.
Automatically switched to ``False`` if ``oneshot_on`` or ``activate_on`` are used.
* ``oneshot_on`` - Set to ``"USR1"``, ``"USR2"`` or some other signal name, or a number if you want the Manhole to
listen for connection in the signal handler. This is desireable in case you don't want threads at all.
* ``sigmask`` - Will set the signal mask to the given list (using ``signalfd.sigprocmask``). No action is done if
``signalfd`` is not importable. **NOTE**: This is done so that the Manhole thread doesn't *steal* any signals;
Normally that is fine because Python will force all the signal handling to be run in the main thread but signalfd
doesn't.
* ``socket_path`` - Use a specific path for the unix domain socket (instead of ``/tmp/manhole-<pid>``). This disables
``patch_fork`` as children cannot reuse the same path.
* ``reinstall_delay`` - Delay the unix domain socket creation *reinstall_delay* seconds. This alleviates
cleanup failures when using fork+exec patterns.
* ``locals`` - Names to add to manhole interactive shell locals.
* ``daemon_connection`` - The connection thread is daemonic (dies on app exit). Default: ``False``.
* ``redirect_stderr`` - Redirect output from stderr to manhole console. Default: ``True``.
* ``strict`` - If ``True`` then ``AlreadyInstalled`` will be raised when attempting to install manhole twice.
Default: ``True``.
Environment variable installation
---------------------------------
Manhole can be installed via the ``PYTHONMANHOLE`` environment variable.
This::
PYTHONMANHOLE='' python yourapp.py
Is equivalent to having this in ``yourapp.py``::
import manhole
manhole.install()
Any extra text in the environment variable is passed to ``manhole.install()``. Example::
PYTHONMANHOLE='oneshot_on="USR2"' python yourapp.py
What happens when you actually connect to the socket
----------------------------------------------------
1. Credentials are checked (if it's same user or root)
2. ``sys.__std*__``/``sys.std*`` are redirected to the UDS
3. Stacktraces for each thread are written to the UDS
4. REPL is started so you can fiddle with the process
Known issues
============
* Using threads and file handle (not raw file descriptor) ``verbose_destination`` can cause deadlocks. See bug reports:
`PyPy <https://github.com/pypy/pypy/issues/1895>`_ and `Python 3.4 <http://bugs.python.org/issue22697>`_.
SIGTERM and socket cleanup
--------------------------
By default Python doesn't call the ``atexit`` callbacks with the default SIGTERM handling. This makes manhole leave
stray socket files around. If this is undesirable you should install a custom SIGTERM handler so ``atexit`` is
properly invoked.
Example:
.. code-block:: python
import signal
import sys
def handle_sigterm(signo, frame):
sys.exit(128 + signo) # this will raise SystemExit and cause atexit to be called
signal.signal(signal.SIGTERM, handle_sigterm)
Using Manhole with uWSGI
------------------------
Because uWSGI overrides signal handling Manhole is a bit more tricky to setup. One way is to use "uWSGI signals" (not
the POSIX signals) and have the workers check a file for the pid you want to open the Manhole in.
Stick something this in your WSGI application file:
.. sourcecode:: python
from __future__ import print_function
import sys
import os
import manhole
stack_dump_file = '/tmp/manhole-pid'
uwsgi_signal_number = 17
try:
import uwsgi
if not os.path.exists(stack_dump_file):
open(stack_dump_file, 'w')
def open_manhole(dummy_signum):
with open(stack_dump_file, 'r') as fh:
pid = fh.read().strip()
if pid == str(os.getpid()):
inst = manhole.install(strict=False, thread=False)
inst.handle_oneshot(dummy_signum, dummy_signum)
uwsgi.register_signal(uwsgi_signal_number, 'workers', open_manhole)
uwsgi.add_file_monitor(uwsgi_signal_number, stack_dump_file)
print("Listening for stack mahole requests via %r" % (stack_dump_file,), file=sys.stderr)
except ImportError:
print("Not running under uwsgi; unable to configure manhole trigger", file=sys.stderr)
except IOError:
print("IOError creating manhole trigger %r" % (stack_dump_file,), file=sys.stderr)
# somewhere bellow you'd have something like
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
# or
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/plain'), ('Content-Length', '2')])
yield b'OK'
To open the Manhole just run `echo 1234 > /tmp/manhole-pid` and then `manhole-cli 1234`.
Requirements
============
:OS: Linux, OS X
:Runtime: Python 2.7, 3.4, 3.5, 3.6 or PyPy
Similar projects
================
* Twisted's `manhole <http://twistedmatrix.com/documents/current/api/twisted.conch.manhole.html>`__ - it has colors and
server-side history.
* `wsgi-shell <https://github.com/GrahamDumpleton/wsgi-shell>`_ - spawns a thread.
* `pyrasite <https://github.com/lmacken/pyrasite>`_ - uses gdb to inject code.
* `pydbattach <https://github.com/albertz/pydbattach>`_ - uses gdb to inject code.
* `pystuck <https://github.com/alonho/pystuck>`_ - very similar, uses `rpyc <https://github.com/tomerfiliba/rpyc>`_ for
communication.
* `pyringe <https://github.com/google/pyringe>`_ - uses gdb to inject code, more reliable, but relies on `dbg` python
builds unfortunatelly.
* `pdb-clone <https://pypi.python.org/pypi/pdb-clone>`_ - uses gdb to inject code, with a `different strategy
<https://code.google.com/p/pdb-clone/wiki/RemoteDebugging>`_.
Changelog
=========
1.8.1 (2024-07-24)
------------------
* Fixed buffering issue on Python 3.11. See ``66``.
* Cleaned up some packaging/test problems.
* Removed more leftover Python 2 code.
* Fixed license metadata. See: ``68``.
1.8.0 (2021-04-08)
------------------
* Simplified connection closing code.
Contributed by Anton Ryzhov in ``62``.
* Made connection shutdown in ``manhole-cli`` more graceful.
Contributed by Anton Ryzhov in ``63``.
1.7.0 (2021-03-22)
------------------
* Fixed memory leak via ``sys.last_type``, ``sys.last_value``, ``sys.last_traceback``.
Contributed by Anton Ryzhov in ``59``.
* Fixed a bunch of double-close bugs and simplified stream handler code.
Contributed by Anton Ryzhov in ``58``.
* Loosen up ``pid`` argument parsing in ``manhole-cli`` to allow using paths with any prefix
(not just ``/tmp``).
1.6.0 (2019-01-19)
------------------
* Testing improvements (changed some skips to xfail, added osx in Travis).
* Fixed long standing Python 2.7 bug where ``sys.getfilesystemencoding()`` would be broken after installing a threaded
manhole. See ``51``.
* Dropped support for Python 2.6, 3.3 and 3.4.
* Fixed handling when ``socket.setdefaulttimeout()`` is used.
Contributed by "honnix" in ``53``.
* Fixed some typos. Contributed by Jesús Cea in ``43``.
* Fixed handling in ``manhole-cli`` so that timeout is actually seconds and not milliseconds.
Contributed by Nir Soffer in ``45``.
* Cleaned up useless polling options in ``manhole-cli``.
Contributed by Nir Soffer in ``46``.
* Documented and implemented a solution for using Manhole with Eventlet.
See ``49``.
1.5.0 (2017-08-31)
------------------
* Added two string aliases for ``connection_handler`` option. Now you can conveniently use ``connection_handler="exec"``.
* Improved ``handle_connection_exec``. It now has a clean way to exit (``exit()``) and properly closes the socket.
1.4.0 (2017-08-29)
------------------
* Added the ``connection_handler`` install option. Default value is ``manhole.handle_connection_repl``, and alternate
``manhole.handle_connection_exec`` is provided (very simple: no output redirection, no stacktrace dumping).
* Dropped Python 3.2 from the test grid. It may work but it's a huge pain to support (pip/pytest don't support it anymore).
* Added Python 3.5 and 3.6 in the test grid.
* Fixed issues with piping to ``manhole-cli``. Now ``echo foobar | manhole-cli`` will wait 1 second for output from manhole
(you can customize this with the ``--timeout`` option).
* Fixed issues with newer PyPy (caused by gevent/eventlet socket unwrapping).
1.3.0 (2015-09-03)
------------------
* Allowed Manhole to be configured without any thread or activation (in case you want to manually activate).
* Added an example and tests for using Manhole with uWSGi.
* Fixed error handling in ``manhole-cli`` on Python 3 (exc vars don't leak anymore).
* Fixed support for running in gevent/eventlet-using apps on Python 3 (now that they support Python 3).
* Allowed reinstalling the manhole (in non-``strict`` mode). Previous install is undone.
1.2.0 (2015-07-06)
------------------
* Changed ``manhole-cli``:
* Won't spam the terminal with errors if socket file doesn't exist.
* Allowed sending any signal (new ``--signal`` argument).
* Fixed some validation issues for the ``PID`` argument.
1.1.0 (2015-06-06)
------------------
* Added support for installing the manhole via the ``PYTHONMANHOLE`` environment variable.
* Added a ``strict`` install option. Set it to false to avoid getting the ``AlreadyInstalled`` exception.
* Added a ``manhole-cli`` script that emulates ``socat readline unix-connect:/tmp/manhole-1234``.
1.0.0 (2014-10-13)
------------------
* Added ``socket_path`` install option (contributed by `Nir Soffer`_).
* Added ``reinstall_delay`` install option.
* Added ``locals`` install option (contributed by `Nir Soffer`_).
* Added ``redirect_stderr`` install option (contributed by `Nir Soffer`_).
* Lots of internals cleanup (contributed by `Nir Soffer`_).
0.6.2 (2014-04-28)
------------------
* Fix OS X regression.
0.6.1 (2014-04-28)
------------------
* Support for OS X (contributed by `Saulius Menkevičius`_).
.. _Saulius Menkevičius: https://github.com/razzmatazz
.. _Nir Soffer: https://github.com/nirs
Raw data
{
"_id": null,
"home_page": "https://github.com/ionelmc/python-manhole",
"name": "manhole",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "debugging, manhole, thread, socket, unix domain socket",
"author": "Ionel Cristian M\u0103rie\u0219",
"author_email": "contact@ionelmc.ro",
"download_url": "https://files.pythonhosted.org/packages/d1/5c/2d1cd4957237b4c46aa8cac77e81780bf4439035a7f83b0a620a0de21bbc/manhole-1.8.1.tar.gz",
"platform": null,
"description": "========\nOverview\n========\n\n\n\n\nFeatures\n========\n\n* Uses unix domain sockets, only root or same effective user can connect.\n* Can run the connection in a thread or in a signal handler (see ``oneshot_on`` option).\n* Can start the thread listening for connections from a signal handler (see ``activate_on`` option)\n* Compatible with apps that fork, reinstalls the Manhole thread after fork - had to monkeypatch os.fork/os.forkpty for\n this.\n* Compatible with gevent and eventlet with some limitations - you need to either:\n\n * Use ``oneshot_on``, *or*\n * Disable thread monkeypatching (eg: ``gevent.monkey.patch_all(thread=False)``, ``eventlet.monkey_patch(thread=False)``\n\n Note: on eventlet `you might <https://github.com/eventlet/eventlet/issues/401>`_ need to setup the hub first to prevent\n circular import problems:\n\n .. sourcecode:: python\n\n import eventlet\n eventlet.hubs.get_hub() # do this first\n eventlet.monkey_patch(thread=False)\n\n* The thread is compatible with apps that use signalfd (will mask all signals for the Manhole threads).\n\nOptions\n-------\n\n.. code-block:: python\n\n manhole.install(\n verbose=True,\n verbose_destination=2,\n patch_fork=True,\n activate_on=None,\n oneshot_on=None,\n sigmask=manhole.ALL_SIGNALS,\n socket_path=None,\n reinstall_delay=0.5,\n locals=None,\n strict=True,\n )\n\n* ``verbose`` - Set it to ``False`` to squelch the logging.\n* ``verbose_destination`` - Destination for verbose messages. Set it to a file descriptor or handle. Default is\n unbuffered stderr (stderr ``2`` file descriptor).\n* ``patch_fork`` - Set it to ``False`` if you don't want your ``os.fork`` and ``os.forkpy`` monkeypatched\n* ``activate_on`` - Set to ``\"USR1\"``, ``\"USR2\"`` or some other signal name, or a number if you want the Manhole thread\n to start when this signal is sent. This is desirable in case you don't want the thread active all the time.\n* ``thread`` - Set to ``True`` to start the always-on ManholeThread. Default: ``True``.\n Automatically switched to ``False`` if ``oneshot_on`` or ``activate_on`` are used.\n* ``oneshot_on`` - Set to ``\"USR1\"``, ``\"USR2\"`` or some other signal name, or a number if you want the Manhole to\n listen for connection in the signal handler. This is desireable in case you don't want threads at all.\n* ``sigmask`` - Will set the signal mask to the given list (using ``signalfd.sigprocmask``). No action is done if\n ``signalfd`` is not importable. **NOTE**: This is done so that the Manhole thread doesn't *steal* any signals;\n Normally that is fine because Python will force all the signal handling to be run in the main thread but signalfd\n doesn't.\n* ``socket_path`` - Use a specific path for the unix domain socket (instead of ``/tmp/manhole-<pid>``). This disables\n ``patch_fork`` as children cannot reuse the same path.\n* ``reinstall_delay`` - Delay the unix domain socket creation *reinstall_delay* seconds. This alleviates\n cleanup failures when using fork+exec patterns.\n* ``locals`` - Names to add to manhole interactive shell locals.\n* ``daemon_connection`` - The connection thread is daemonic (dies on app exit). Default: ``False``.\n* ``redirect_stderr`` - Redirect output from stderr to manhole console. Default: ``True``.\n* ``strict`` - If ``True`` then ``AlreadyInstalled`` will be raised when attempting to install manhole twice.\n Default: ``True``.\n\nEnvironment variable installation\n---------------------------------\n\nManhole can be installed via the ``PYTHONMANHOLE`` environment variable.\n\nThis::\n\n PYTHONMANHOLE='' python yourapp.py\n\nIs equivalent to having this in ``yourapp.py``::\n\n import manhole\n manhole.install()\n\nAny extra text in the environment variable is passed to ``manhole.install()``. Example::\n\n PYTHONMANHOLE='oneshot_on=\"USR2\"' python yourapp.py\n\nWhat happens when you actually connect to the socket\n----------------------------------------------------\n\n1. Credentials are checked (if it's same user or root)\n2. ``sys.__std*__``/``sys.std*`` are redirected to the UDS\n3. Stacktraces for each thread are written to the UDS\n4. REPL is started so you can fiddle with the process\n\nKnown issues\n============\n\n* Using threads and file handle (not raw file descriptor) ``verbose_destination`` can cause deadlocks. See bug reports:\n `PyPy <https://github.com/pypy/pypy/issues/1895>`_ and `Python 3.4 <http://bugs.python.org/issue22697>`_.\n\nSIGTERM and socket cleanup\n--------------------------\n\nBy default Python doesn't call the ``atexit`` callbacks with the default SIGTERM handling. This makes manhole leave\nstray socket files around. If this is undesirable you should install a custom SIGTERM handler so ``atexit`` is\nproperly invoked.\n\nExample:\n\n.. code-block:: python\n\n import signal\n import sys\n\n def handle_sigterm(signo, frame):\n sys.exit(128 + signo) # this will raise SystemExit and cause atexit to be called\n\n signal.signal(signal.SIGTERM, handle_sigterm)\n\nUsing Manhole with uWSGI\n------------------------\n\nBecause uWSGI overrides signal handling Manhole is a bit more tricky to setup. One way is to use \"uWSGI signals\" (not\nthe POSIX signals) and have the workers check a file for the pid you want to open the Manhole in.\n\nStick something this in your WSGI application file:\n\n.. sourcecode:: python\n\n from __future__ import print_function\n import sys\n import os\n import manhole\n\n stack_dump_file = '/tmp/manhole-pid'\n uwsgi_signal_number = 17\n\n try:\n import uwsgi\n\n if not os.path.exists(stack_dump_file):\n open(stack_dump_file, 'w')\n\n def open_manhole(dummy_signum):\n with open(stack_dump_file, 'r') as fh:\n pid = fh.read().strip()\n if pid == str(os.getpid()):\n inst = manhole.install(strict=False, thread=False)\n inst.handle_oneshot(dummy_signum, dummy_signum)\n\n uwsgi.register_signal(uwsgi_signal_number, 'workers', open_manhole)\n uwsgi.add_file_monitor(uwsgi_signal_number, stack_dump_file)\n\n print(\"Listening for stack mahole requests via %r\" % (stack_dump_file,), file=sys.stderr)\n except ImportError:\n print(\"Not running under uwsgi; unable to configure manhole trigger\", file=sys.stderr)\n except IOError:\n print(\"IOError creating manhole trigger %r\" % (stack_dump_file,), file=sys.stderr)\n\n\n # somewhere bellow you'd have something like\n from django.core.wsgi import get_wsgi_application\n application = get_wsgi_application()\n # or\n def application(environ, start_response):\n start_response('200 OK', [('Content-Type', 'text/plain'), ('Content-Length', '2')])\n yield b'OK'\n\nTo open the Manhole just run `echo 1234 > /tmp/manhole-pid` and then `manhole-cli 1234`.\n\nRequirements\n============\n\n:OS: Linux, OS X\n:Runtime: Python 2.7, 3.4, 3.5, 3.6 or PyPy\n\nSimilar projects\n================\n\n* Twisted's `manhole <http://twistedmatrix.com/documents/current/api/twisted.conch.manhole.html>`__ - it has colors and\n server-side history.\n* `wsgi-shell <https://github.com/GrahamDumpleton/wsgi-shell>`_ - spawns a thread.\n* `pyrasite <https://github.com/lmacken/pyrasite>`_ - uses gdb to inject code.\n* `pydbattach <https://github.com/albertz/pydbattach>`_ - uses gdb to inject code.\n* `pystuck <https://github.com/alonho/pystuck>`_ - very similar, uses `rpyc <https://github.com/tomerfiliba/rpyc>`_ for\n communication.\n* `pyringe <https://github.com/google/pyringe>`_ - uses gdb to inject code, more reliable, but relies on `dbg` python\n builds unfortunatelly.\n* `pdb-clone <https://pypi.python.org/pypi/pdb-clone>`_ - uses gdb to inject code, with a `different strategy\n <https://code.google.com/p/pdb-clone/wiki/RemoteDebugging>`_.\n\n\nChangelog\n=========\n\n1.8.1 (2024-07-24)\n------------------\n\n* Fixed buffering issue on Python 3.11. See ``66``.\n* Cleaned up some packaging/test problems.\n* Removed more leftover Python 2 code.\n* Fixed license metadata. See: ``68``.\n\n1.8.0 (2021-04-08)\n------------------\n\n* Simplified connection closing code.\n Contributed by Anton Ryzhov in ``62``.\n* Made connection shutdown in ``manhole-cli`` more graceful.\n Contributed by Anton Ryzhov in ``63``.\n\n1.7.0 (2021-03-22)\n------------------\n\n* Fixed memory leak via ``sys.last_type``, ``sys.last_value``, ``sys.last_traceback``.\n Contributed by Anton Ryzhov in ``59``.\n* Fixed a bunch of double-close bugs and simplified stream handler code.\n Contributed by Anton Ryzhov in ``58``.\n* Loosen up ``pid`` argument parsing in ``manhole-cli`` to allow using paths with any prefix\n (not just ``/tmp``).\n\n1.6.0 (2019-01-19)\n------------------\n\n* Testing improvements (changed some skips to xfail, added osx in Travis).\n* Fixed long standing Python 2.7 bug where ``sys.getfilesystemencoding()`` would be broken after installing a threaded\n manhole. See ``51``.\n* Dropped support for Python 2.6, 3.3 and 3.4.\n* Fixed handling when ``socket.setdefaulttimeout()`` is used.\n Contributed by \"honnix\" in ``53``.\n* Fixed some typos. Contributed by Jes\u00fas Cea in ``43``.\n* Fixed handling in ``manhole-cli`` so that timeout is actually seconds and not milliseconds.\n Contributed by Nir Soffer in ``45``.\n* Cleaned up useless polling options in ``manhole-cli``.\n Contributed by Nir Soffer in ``46``.\n* Documented and implemented a solution for using Manhole with Eventlet.\n See ``49``.\n\n1.5.0 (2017-08-31)\n------------------\n\n* Added two string aliases for ``connection_handler`` option. Now you can conveniently use ``connection_handler=\"exec\"``.\n* Improved ``handle_connection_exec``. It now has a clean way to exit (``exit()``) and properly closes the socket.\n\n1.4.0 (2017-08-29)\n------------------\n\n* Added the ``connection_handler`` install option. Default value is ``manhole.handle_connection_repl``, and alternate\n ``manhole.handle_connection_exec`` is provided (very simple: no output redirection, no stacktrace dumping).\n* Dropped Python 3.2 from the test grid. It may work but it's a huge pain to support (pip/pytest don't support it anymore).\n* Added Python 3.5 and 3.6 in the test grid.\n* Fixed issues with piping to ``manhole-cli``. Now ``echo foobar | manhole-cli`` will wait 1 second for output from manhole\n (you can customize this with the ``--timeout`` option).\n* Fixed issues with newer PyPy (caused by gevent/eventlet socket unwrapping).\n\n1.3.0 (2015-09-03)\n------------------\n\n* Allowed Manhole to be configured without any thread or activation (in case you want to manually activate).\n* Added an example and tests for using Manhole with uWSGi.\n* Fixed error handling in ``manhole-cli`` on Python 3 (exc vars don't leak anymore).\n* Fixed support for running in gevent/eventlet-using apps on Python 3 (now that they support Python 3).\n* Allowed reinstalling the manhole (in non-``strict`` mode). Previous install is undone.\n\n1.2.0 (2015-07-06)\n------------------\n\n* Changed ``manhole-cli``:\n\n * Won't spam the terminal with errors if socket file doesn't exist.\n * Allowed sending any signal (new ``--signal`` argument).\n * Fixed some validation issues for the ``PID`` argument.\n\n1.1.0 (2015-06-06)\n------------------\n\n* Added support for installing the manhole via the ``PYTHONMANHOLE`` environment variable.\n* Added a ``strict`` install option. Set it to false to avoid getting the ``AlreadyInstalled`` exception.\n* Added a ``manhole-cli`` script that emulates ``socat readline unix-connect:/tmp/manhole-1234``.\n\n1.0.0 (2014-10-13)\n------------------\n\n* Added ``socket_path`` install option (contributed by `Nir Soffer`_).\n* Added ``reinstall_delay`` install option.\n* Added ``locals`` install option (contributed by `Nir Soffer`_).\n* Added ``redirect_stderr`` install option (contributed by `Nir Soffer`_).\n* Lots of internals cleanup (contributed by `Nir Soffer`_).\n\n0.6.2 (2014-04-28)\n------------------\n\n* Fix OS X regression.\n\n0.6.1 (2014-04-28)\n------------------\n\n* Support for OS X (contributed by `Saulius Menkevi\u010dius`_).\n\n.. _Saulius Menkevi\u010dius: https://github.com/razzmatazz\n.. _Nir Soffer: https://github.com/nirs\n",
"bugtrack_url": null,
"license": "BSD-2-Clause",
"summary": "Manhole is in-process service that will accept unix domain socket connections and present thestacktraces for all threads and an interactive prompt.",
"version": "1.8.1",
"project_urls": {
"Changelog": "https://python-manhole.readthedocs.io/en/latest/changelog.html",
"Documentation": "https://python-manhole.readthedocs.io/",
"Homepage": "https://github.com/ionelmc/python-manhole",
"Issue Tracker": "https://github.com/ionelmc/python-manhole/issues"
},
"split_keywords": [
"debugging",
" manhole",
" thread",
" socket",
" unix domain socket"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "274f70f87a63cc40f8f52ba5549c77f7f9e82a38e35d70f0b46a157eb5cabba8",
"md5": "56112237d39bce28047cec96b28cacb1",
"sha256": "35e4d051776fa375beb8a512994627a297ee16ee43618e8d4b9c486fe85b1729"
},
"downloads": -1,
"filename": "manhole-1.8.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "56112237d39bce28047cec96b28cacb1",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 16347,
"upload_time": "2024-07-04T16:25:34",
"upload_time_iso_8601": "2024-07-04T16:25:34.706273Z",
"url": "https://files.pythonhosted.org/packages/27/4f/70f87a63cc40f8f52ba5549c77f7f9e82a38e35d70f0b46a157eb5cabba8/manhole-1.8.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "d15c2d1cd4957237b4c46aa8cac77e81780bf4439035a7f83b0a620a0de21bbc",
"md5": "f464d2b4f7772a513ce2db2176d90cb6",
"sha256": "3668fdaf83b33c943db4e750e0c554e31c20f63338496895dd4d6410680d9c4b"
},
"downloads": -1,
"filename": "manhole-1.8.1.tar.gz",
"has_sig": false,
"md5_digest": "f464d2b4f7772a513ce2db2176d90cb6",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 41058,
"upload_time": "2024-07-04T16:25:36",
"upload_time_iso_8601": "2024-07-04T16:25:36.987001Z",
"url": "https://files.pythonhosted.org/packages/d1/5c/2d1cd4957237b4c46aa8cac77e81780bf4439035a7f83b0a620a0de21bbc/manhole-1.8.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-07-04 16:25:36",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "ionelmc",
"github_project": "python-manhole",
"travis_ci": false,
"coveralls": true,
"github_actions": true,
"tox": true,
"lcname": "manhole"
}