From 0fa5fe5559341bf73414246cda1bd9ec32334b64 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Tue, 2 Oct 2018 21:13:05 +0100 Subject: [PATCH] parent: handle masters with blank sys.executable; closes #356. --- docs/changelog.rst | 5 +++++ mitogen/fakessh.py | 4 ++-- mitogen/parent.py | 26 +++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 6f5ac94e..aeaa36f5 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -174,6 +174,11 @@ Core Library * `#345 `_: the SSH connection method allows optionally disabling ``IdentitiesOnly yes``. +* `#356 `_: if the master Python + process does not have :data:`sys.executable` set, the default Python + interpreter used for new children on the local machine defaults to + ``"/usr/bin/python"``. + * `#366 `_, `#380 `_: attempts by children to import :mod:`__main__` where the main program module lacks an execution guard diff --git a/mitogen/fakessh.py b/mitogen/fakessh.py index 5667bcad..582017bc 100644 --- a/mitogen/fakessh.py +++ b/mitogen/fakessh.py @@ -436,7 +436,7 @@ def run(dest, router, args, deadline=None, econtext=None): ssh_path = os.path.join(tmp_path, 'ssh') fp = open(ssh_path, 'w') try: - fp.write('#!%s\n' % (sys.executable,)) + fp.write('#!%s\n' % (mitogen.parent.get_sys_executable(),)) fp.write(inspect.getsource(mitogen.core)) fp.write('\n') fp.write('ExternalContext(%r).main()\n' % ( @@ -449,7 +449,7 @@ def run(dest, router, args, deadline=None, econtext=None): env = os.environ.copy() env.update({ 'PATH': '%s:%s' % (tmp_path, env.get('PATH', '')), - 'ARGV0': sys.executable, + 'ARGV0': mitogen.parent.get_sys_executable(), 'SSH_PATH': ssh_path, }) diff --git a/mitogen/parent.py b/mitogen/parent.py index fe5e6889..a4e17b93 100644 --- a/mitogen/parent.py +++ b/mitogen/parent.py @@ -85,11 +85,35 @@ OPENPTY_MSG = ( "to avoid PTY use." ) +SYS_EXECUTABLE_MSG = ( + "The Python sys.executable variable is unset, indicating Python was " + "unable to determine its original program name. Unless explicitly " + "configured otherwise, child contexts will be started using " + "'/usr/bin/python'" +) +_sys_executable_warning_logged = False + def get_log_level(): return (LOG.level or logging.getLogger().level or logging.INFO) +def get_sys_executable(): + """ + Return :data:`sys.executable` if it is set, otherwise return + ``"/usr/bin/python"`` and log a warning. + """ + if sys.executable: + return sys.executable + + global _sys_executable_warning_logged + if not _sys_executable_warning_logged: + LOG.warn(SYS_EXECUTABLE_MSG) + _sys_executable_warning_logged = True + + return '/usr/bin/python' + + def get_core_source(): """ In non-masters, simply fetch the cached mitogen.core source code via the @@ -841,7 +865,7 @@ class Stream(mitogen.core.Stream): Base for streams capable of starting new slaves. """ #: The path to the remote Python interpreter. - python_path = sys.executable + python_path = get_sys_executable() #: Maximum time to wait for a connection attempt. connect_timeout = 30.0