def get_real_python():
     """
     The reason why the virtualenv creation is proxied by this function is mostly
     because under windows, we can't seem to properly create a virtualenv off of
     another virtualenv(we can on Linux) and also because, we really don't want to
     test virtualenv creation off of another virtualenv, we want a virtualenv created
     from the original python.
     Also, on windows, we must also point to the virtualenv binary outside the existing
     virtualenv because it will fail otherwise
     """
     try:
         if platform.is_windows():
             return os.path.join(sys.real_prefix,
                                 os.path.basename(sys.executable))
         else:
             python_binary_names = [
                 "python{}.{}".format(*sys.version_info),
                 "python{}".format(*sys.version_info),
                 "python",
             ]
             for binary_name in python_binary_names:
                 python = os.path.join(sys.real_prefix, "bin", binary_name)
                 if os.path.exists(python):
                     break
             else:
                 raise AssertionError(
                     "Couldn't find a python binary name under '{}' matching: {}"
                     .format(os.path.join(sys.real_prefix, "bin"),
                             python_binary_names))
             return python
     except AttributeError:
         return sys.executable
def test_daemon_process_termination(request, tempfiles):
    primary_childrend_count = 5
    secondary_children_count = 3
    script = tempfiles.makepyfile(
        """
        #!{shebang}
        # coding=utf-8

        import time
        import multiprocessing

        def spin():
            while True:
                try:
                    time.sleep(0.25)
                except KeyboardInterrupt:
                    break

        def spin_children():
            procs = []
            for idx in range({secondary_children_count}):
                proc = multiprocessing.Process(target=spin)
                proc.daemon = True
                proc.start()
                procs.append(proc)

            while True:
                try:
                    time.sleep(0.25)
                except KeyboardInterrupt:
                    break


        def main():
            procs = []

            for idx in range({primary_childrend_count}):
                proc = multiprocessing.Process(target=spin_children)
                procs.append(proc)
                proc.start()

            while True:
                try:
                    time.sleep(0.25)
                except KeyboardInterrupt:
                    break

            # We're not terminating child processes on purpose. Our code should handle it.

        # Support for windows test runs
        if __name__ == '__main__':
            multiprocessing.freeze_support()
            main()
        """.format(
            shebang=sys.executable,
            primary_childrend_count=primary_childrend_count,
            secondary_children_count=secondary_children_count,
        ),
        executable=True,
    )
    if not platform.is_windows():
        factory_kwargs = dict(cli_script_name=script)
    else:
        # Windows don't know how to handle python scripts directly
        factory_kwargs = dict(cli_script_name=sys.executable, base_script_args=[script])
    daemon = DaemonFactory(**factory_kwargs)
    daemon.start()
    daemon_pid = daemon.pid
    # Make sure the daemon is terminated no matter what
    request.addfinalizer(daemon.terminate)
    # Allow the script to start
    time.sleep(PROCESS_START_TIMEOUT)
    assert psutil.pid_exists(daemon_pid)
    proc = psutil.Process(daemon_pid)
    children = proc.children(recursive=True)
    request.addfinalizer(functools.partial(kill_children, children))
    assert len(children) == primary_childrend_count + (
        primary_childrend_count * secondary_children_count
    )
    daemon.terminate()
    assert psutil.pid_exists(daemon_pid) is False
    for child in list(children):
        if psutil.pid_exists(child.pid):
            continue
        children.remove(child)
    assert not children, "len(children)=={} != 0\n{}".format(
        len(children), pprint.pformat(children)
    )
 def _default_log_host(self):
     if platform.is_windows():
         # Windows cannot bind to 0.0.0.0
         return "127.0.0.1"
     return "0.0.0.0"
 def _default_venv_python(self):
     # Once we drop Py3.5 we can stop casting to string
     if platform.is_windows():
         return str(self.venv_dir / "Scripts" / "python.exe")
     return str(self.venv_dir / "bin" / "python")