<type>documentation</type>
<domain>debug</domain>
<id>child-processes</id>
<title>Debugging Child Processes</title>
<date>$Date: 2007-05-09 16:44:39 -0400 (Wed, 09 May 2007) $</date>
<version>$Revision: 15504 $</version>
<product>pro+</product>

Sub-processes started with the Python ``multiprocessing`` module or with ``os.fork()`` may
be debugged automatically, so that each child process appears as a separate debug process
in Wing. This is disabled by default but can be enabled with the `Debugger > Processes >
Debug Child Processes
<script:show_preferences_gui#prefname="debug.multi-process-debug-sub-processes">`__
preference or by setting `Debug/Execute > Debug Child Processes
<script:view_project_properties#highlighted_attrib="proj.debug-sub-processes">`__ in
``Project Properties``.

Sub-processes started with ``os.system()``, ``CreateProcess`` (on Windows), ``os.exec()``
(on Posix), or similar calls will not be debugged automatically because the OS completely
replaces the parent process context and there is no way to keep a debug connection intact.
However, it is still possible to debug processes launched in this way by manually
initiating debug in the sub-process as described in `Debugging Externally Launched Code
<ref:debug/debugging-externally-launched-code>`__.

Notice that processes started by ``os.fork()`` followed by ``os.exec()`` will be debugged
only for the (usually brief) period of time between the ``os.fork()`` and ``os.exec()``
calls.

**Debugging Child Processes Created with sys.executable**

By default when debugging sub-processes is enabled, Wing replaces ``sys.executable`` to
cover some of the common ways in which sub-processes may be launched, particularly on
Windows. This can be disabled with the `Debugger > Processes > Replace sys.executable
<script:show_preferences_gui#prefname="debug.multi-process-replace-sys-executable">`__
preference.

Because the ``multiprocessing`` standard library module uses ``sys.executable`` to launch
its children, this option must be enabled in order to debug children created by that module.

Wing replaces ``sys.executable`` at startup only. As a result, user code that alters the
value (other than by calling ``multiprocessing.forking.set_executable``) will break
debugging of child processes that are launched with a command line that contains
``sys.executable``.

When ``sys.executable`` replacement is enabled, code that invokes ``sys.executable`` to
start a child process must also provide the environment variables starting with
``WINGDB_`` to the child process. Otherwise, the debugger cannot determine which Python to
run or how to connect to the IDE and the child process will fail to start.

If child processes are created with ``sys.executable`` the code that starts the child
processes will need to correctly handle spaces in the path within ``sys.executable``.
Otherwise, child processes will fail to launch if Wing is installed into a directory path
that has spaces in it and child process debugging is enabled.

One way to work around cases where ``sys.executable`` replacement does not work is to
manually initiating debug in the sub-process as described in `Debugging Externally
Launched Code <ref:debug/debugging-externally-launched-code>`__.

**Target Processes for Handles on Windows**

Replacing ``sys.executable`` will cause problems on Windows if a parent process launches
children with a command line that contains a ``Handle`` created specifically for its child
process, for example by setting ``hTargetProcessHandle`` in a call to ``DuplicateHandle``.
In this case, the handle will be invalid in the child because replacing ``sys.executable``
creates an intervening process and the child runs as the grand-child instead.

If a ``Handle`` is instead set to be inheritable for all child processes, for example by
setting ``bInheritHandle`` in a call to ``DuplicateHandle``, then replacing
``sys.executable`` will work without any problems.

**Other Notes and Limitations**

When debugging child processes created with the ``multiprocessing`` module, Wing will stop
on exceptions raised in child processes. Continuing debug from that point will pack up and
return the exception to the parent process, as in normal operation. Exceptions in children
can be ignored with the ``Ignore this exception location`` checkbox in the ``Exceptions``
tool.

Overriding the ``_bootstrap`` method of ``multiprocessing.process.Process`` (or
``multiprocessing.process.BaseProcess`` in Python 3.4+) in a custom process class will
prevent Wing from stopping on exceptions in child processes unless the exception is
propagated to the inherited method. A work-around for this would be to call
``logging.exception`` with any exception before sending it out to the parent process.

Some approaches to spawning child processes may result in the creation of intermediate
processes that appear in Wing's process tree display. For example, using the
``shell=True`` option in ``subprocess.Popen`` will do this on Linux. When setting
``shell=False`` you may need to change the command passed to ``Popen`` to a list rather
than a string.

Debug overhead may reveal timing bugs not seen outside of the debugger. For example, a
parent process may attempt to interact with a child process too quickly, causing problems
only under the debugger. This is particularly likely on Windows, where there is an
intermediate process created between the parent and child process.

