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 get_base_script_args(self): """ Return the base arguments for the daemon. """ script_args = super().get_base_script_args() if platform.is_windows() is False: script_args.append("--disable-keepalive") return script_args
def get_script_args(self): """ Return the script arguments. """ args = super().get_script_args() if platform.is_windows() is False: args.append("--disable-keepalive") return args
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(script_name=script) else: # Windows don't know how to handle python scripts directly factory_kwargs = dict(script_name=sys.executable, base_script_args=[script]) daemon = Daemon(start_timeout=1, **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)) child_count = len(children) expected_count = primary_childrend_count + (primary_childrend_count * secondary_children_count) if platform.is_windows() and sys.version_info[:2] == (3, 7): # Under Python 3.7 and Windows we always seem to get +1 child # XXX: Don't forget to look what this extra child is expected_count += 1 assert child_count == expected_count, "{}!={}\n{}".format( child_count, expected_count, pprint.pformat([_get_cmdline(child) or child for child in children]), ) daemon.terminate() assert psutil.pid_exists(daemon_pid) is False for child in list(children): # pragma: no cover if psutil.pid_exists(child.pid): continue children.remove(child) assert not children, "len(children)=={} != 0\n{}".format( len(children), pprint.pformat([_get_cmdline(child) or child for child in children]) )
def test_daemon_process_termination_parent_killed(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(script_name=script) else: # Windows don't know how to handle python scripts directly factory_kwargs = dict(script_name=sys.executable, base_script_args=[script]) daemon = Daemon(start_timeout=1, **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 ) # Pretend the parent process died. proc.kill() time.sleep(0.5) # We should should still be able to terminate all child processes daemon.terminate() assert psutil.pid_exists(daemon_pid) is False psutil.wait_procs(children, timeout=3) 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")
def get_base_script_args(self): script_args = super().get_base_script_args() if platform.is_windows() is False: script_args.append("--disable-keepalive") return script_args