manhole


Namemanhole JSON
Version 1.8.1 PyPI version JSON
download
home_pagehttps://github.com/ionelmc/python-manhole
SummaryManhole is in-process service that will accept unix domain socket connections and present thestacktraces for all threads and an interactive prompt.
upload_time2024-07-04 16:25:36
maintainerNone
docs_urlNone
authorIonel Cristian Mărieș
requires_python>=3.8
licenseBSD-2-Clause
keywords debugging manhole thread socket unix domain socket
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage
            ========
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"
}
        
Elapsed time: 1.04900s