Added THREAD_SUBPROCS env var

This commit is contained in:
Anthony Scopatz 2019-10-05 16:37:45 -04:00
parent 69df412445
commit dc8728bdaf
4 changed files with 56 additions and 2 deletions

View file

@ -6,6 +6,7 @@ import re
import builtins import builtins
import types import types
from ast import AST, Module, Interactive, Expression from ast import AST, Module, Interactive, Expression
from subprocess import Popen
import pytest import pytest
@ -25,8 +26,10 @@ from xonsh.built_ins import (
in_macro_call, in_macro_call,
call_macro, call_macro,
enter_macro, enter_macro,
cmds_to_specs,
) )
from xonsh.environ import Env from xonsh.environ import Env
from xonsh.proc import PopenThread, ProcProxy, ProcProxyThread
from tools import skip_if_on_windows from tools import skip_if_on_windows
@ -388,3 +391,28 @@ def test_enter_macro():
assert obj.macro_block == "wakka" assert obj.macro_block == "wakka"
assert obj.macro_globals assert obj.macro_globals
assert obj.macro_locals assert obj.macro_locals
@skip_if_on_windows
def test_cmds_to_specs_thread_subproc(xonsh_builtins):
env = xonsh_builtins.__xonsh__.env
cmds = [["pwd"]]
# First check that threadable subprocs become threadable
env['THREAD_SUBPROCS'] = True
specs = cmds_to_specs(cmds, captured='hiddenobject')
assert specs[0].cls is PopenThread
# turn off threading and check we use Popen
env['THREAD_SUBPROCS'] = False
specs = cmds_to_specs(cmds, captured='hiddenobject')
assert specs[0].cls is Popen
# now check the threadbility of callable aliases
cmds = [[lambda: "Keras Selyrian"]]
# check that threadable alias become threadable
env['THREAD_SUBPROCS'] = True
specs = cmds_to_specs(cmds, captured='hiddenobject')
assert specs[0].cls is ProcProxyThread
# turn off threading and check we use ProcProxy
env['THREAD_SUBPROCS'] = False
specs = cmds_to_specs(cmds, captured='hiddenobject')
assert specs[0].cls is ProcProxy

View file

@ -738,7 +738,8 @@ class SubprocSpec:
if not callable(alias): if not callable(alias):
return return
self.is_proxy = True self.is_proxy = True
thable = getattr(alias, "__xonsh_threadable__", True) env = builtins.__xonsh__.env
thable = env.get('THREAD_SUBPROCS') and getattr(alias, "__xonsh_threadable__", True)
cls = ProcProxyThread if thable else ProcProxy cls = ProcProxyThread if thable else ProcProxy
self.cls = cls self.cls = cls
self.threadable = thable self.threadable = thable
@ -790,6 +791,7 @@ def _safe_pipe_properties(fd, use_tty=False):
def _update_last_spec(last): def _update_last_spec(last):
env = builtins.__xonsh__.env
captured = last.captured captured = last.captured
last.last_in_pipeline = True last.last_in_pipeline = True
if not captured: if not captured:
@ -799,7 +801,7 @@ def _update_last_spec(last):
pass pass
else: else:
cmds_cache = builtins.__xonsh__.commands_cache cmds_cache = builtins.__xonsh__.commands_cache
thable = cmds_cache.predict_threadable( thable = env.get('THREAD_SUBPROCS') and cmds_cache.predict_threadable(
last.args last.args
) and cmds_cache.predict_threadable(last.cmd) ) and cmds_cache.predict_threadable(last.cmd)
if captured and thable: if captured and thable:

View file

@ -571,6 +571,7 @@ def DEFAULT_ENSURERS():
"SUGGEST_MAX_NUM": (is_int, int, str), "SUGGEST_MAX_NUM": (is_int, int, str),
"SUGGEST_THRESHOLD": (is_int, int, str), "SUGGEST_THRESHOLD": (is_int, int, str),
"SUPPRESS_BRANCH_TIMEOUT_MESSAGE": (is_bool, to_bool, bool_to_str), "SUPPRESS_BRANCH_TIMEOUT_MESSAGE": (is_bool, to_bool, bool_to_str),
"THREAD_SUBPROCS": (is_bool, to_bool, bool_to_str),
"UPDATE_COMPLETIONS_ON_KEYPRESS": (is_bool, to_bool, bool_to_str), "UPDATE_COMPLETIONS_ON_KEYPRESS": (is_bool, to_bool, bool_to_str),
"UPDATE_OS_ENVIRON": (is_bool, to_bool, bool_to_str), "UPDATE_OS_ENVIRON": (is_bool, to_bool, bool_to_str),
"UPDATE_PROMPT_ON_KEYPRESS": (is_bool, to_bool, bool_to_str), "UPDATE_PROMPT_ON_KEYPRESS": (is_bool, to_bool, bool_to_str),
@ -755,6 +756,7 @@ def DEFAULT_VALUES():
"SUGGEST_COMMANDS": True, "SUGGEST_COMMANDS": True,
"SUGGEST_MAX_NUM": 5, "SUGGEST_MAX_NUM": 5,
"SUGGEST_THRESHOLD": 3, "SUGGEST_THRESHOLD": 3,
"THREAD_SUBPROCS": True,
"TITLE": DEFAULT_TITLE, "TITLE": DEFAULT_TITLE,
"UPDATE_COMPLETIONS_ON_KEYPRESS": False, "UPDATE_COMPLETIONS_ON_KEYPRESS": False,
"UPDATE_OS_ENVIRON": False, "UPDATE_OS_ENVIRON": False,
@ -1159,6 +1161,26 @@ def DEFAULT_DOCS():
"not always happen.", "not always happen.",
configurable=False, configurable=False,
), ),
"THREAD_SUBPROCS": VarDocs(
"Whether or not to try to run subrocess mode in a Python thread, "
"when applicable. There are various trade-offs, which normally "
"affects only interactive sessions.\n\nWhen True:\n\n"
"* Xonsh is able capture & store the stdin, stdout, and stderr \n"
" of threadable subprocesses.\n"
"* However, stopping threaded suprocs with ^Z (i.e. ``SIGTSTP``)\n"
" is disabled as it causes deadlocked terminals.\n"
" ``SIGTSTP`` may still be issued and only the physical pressing\n"
" of ``Ctrl+Z`` is ignored.\n"
"* Thredable commands are run with ``PopenThread`` and threadable \n"
" alias are run with ``ProcProxyThread``.\n\n"
"When False:\n\n"
"* Xonsh may not be able to capture stdin, stdout, and stderr streams \n"
" unless explicitly asked to do so.\n"
"* Stopping the thread with yields to job control.\n"
"* Thredable commands are run with ``Popen`` and threadable \n"
" alias are run with ``ProcProxy``.\n\n"
"The desired effect is often up to the command, user, or use case."
),
"TITLE": VarDocs( "TITLE": VarDocs(
"The title text for the window in which xonsh is running. Formatted " "The title text for the window in which xonsh is running. Formatted "
"in the same manner as ``$PROMPT``, see 'Customizing the Prompt' " "in the same manner as ``$PROMPT``, see 'Customizing the Prompt' "

View file

@ -2,6 +2,7 @@
import shlex import shlex
import sys import sys
import re import re
import builtins
__all__ = () __all__ = ()
@ -62,3 +63,4 @@ def alias(args, stdin=None):
aliases["alias"] = alias aliases["alias"] = alias
builtins.__xonsh__.env['THREAD_SUBPROCS'] = False