Merge pull request #2998 from bskinn/venv-prompt

Implement VIRTUAL_ENV_PROMPT and VIRTUAL_ENV_DISABLE_PROMPT
This commit is contained in:
Anthony Scopatz 2019-01-31 10:14:50 -05:00 committed by GitHub
commit 4135c690dc
Failed to generate hash of commit
6 changed files with 154 additions and 10 deletions

View file

@ -1422,7 +1422,9 @@ By default, the following variables are available for use:
``/path/to/xonsh``.
* ``cwd_base``: The basename of the current working directory, e.g. ``xonsh`` in
``/path/to/xonsh``.
* ``env_name``: The name of active virtual environment, if any.
* ``env_name``: The name of active virtual environment, if any. The rendering
of this variable is affected by the ``$VIRTUAL_ENV_PROMPT`` and
``$VIRTUAL_ENV_DISABLE_PROMPT`` environment variables; see below.
* ``env_prefix``: The prefix characters if there is an active virtual environment,
defaults to ``"("``.
* ``env_postfix``: The postfix characters if there is an active virtual environment,
@ -1441,6 +1443,33 @@ By default, the following variables are available for use:
* ``gitstatus``: Informative git status, like ``[master|MERGING|+1…2]``, you
may use `$XONSH_GITSTATUS_* <envvars.html>`_ to customize the styling.
xonsh obeys the ``$VIRTUAL_ENV_DISABLE_PROMPT`` environment variable
`as defined by virtualenv <https://virtualenv.pypa.io/en/latest/reference/
#envvar-VIRTUAL_ENV_DISABLE_PROMPT>`__. If this variable is truthy, xonsh
will *always* substitute an empty string for ``{env_name}``. Note that unlike
with other shells, ``$VIRTUAL_ENV_DISABLE_PROMPT`` takes effect *immediately*
after being set---it is not necessary to re-activate the environment.
xonsh also allows for an explicit override of the rendering of ``{env_name}``,
via the ``$VIRTUAL_ENV_PROMPT`` environment variable. If this variable is
defined and has any value other than ``None``, ``{env_name}`` will *always*
render as ``str($VIRTUAL_ENV_PROMPT)`` when an environment is activated.
It will still render as an empty string when no environment is active.
``$VIRTUAL_ENV_PROMPT`` is overridden by ``$VIRTUAL_ENV_DISABLE_PROMPT``.
For example:
.. code-block:: xonshcon
>>> $PROMPT = '{env_name}>>> '
>>> source env/bin/activate.xsh
(env) >>> $VIRTUAL_ENV_PROMPT = '~~ACTIVE~~ '
~~ACTIVE~~ >>> $VIRTUAL_ENV_DISABLE_PROMPT = 1
>>> del $VIRTUAL_ENV_PROMPT
>>> del $VIRTUAL_ENV_DISABLE_PROMPT
(env) >>>
You can also color your prompt easily by inserting keywords such as ``{GREEN}``
or ``{BOLD_BLUE}``. Colors have the form shown below:

View file

@ -6,7 +6,7 @@
**Changed:**
* ``env_name`` prompt field now looks up the pre- and post-fix characters,
rather than relying on hard-coded values/
rather than relying on hard-coded values.
**Deprecated:**

29
news/prompt-env-vars.rst Normal file
View file

@ -0,0 +1,29 @@
**Added:**
* Rendering of ``{env_name}`` in ``$PROMPT`` is now suppressed if
the ``$VIRTUAL_ENV_DISABLE_PROMPT`` environment variable is
defined and truthy.
* Rendering of ``{env_name}`` in ``$PROMPT`` is now overridden by
the value of ``str($VIRTUAL_ENV_PROMPT)`` if that environment variable
is defined and ``not None``. ``$VIRTUAL_ENV_DISABLE_PROMPT`` takes precedence
over ``$VIRTUAL_ENV_PROMPT``.
**Changed:**
* <news item>
**Deprecated:**
* <news item>
**Removed:**
* <news item>
**Fixed:**
* <news item>
**Security:**
* <news item>

View file

@ -6,7 +6,7 @@ from unittest.mock import Mock
import pytest
from xonsh.environ import Env
from xonsh.prompt.base import PromptFormatter
from xonsh.prompt.base import PromptFormatter, PROMPT_FIELDS
from xonsh.prompt import vc
from tools import skip_if_py34, DummyEnv
@ -17,6 +17,11 @@ def formatter(xonsh_builtins):
return PromptFormatter()
@pytest.fixture
def live_fields():
return PROMPT_FIELDS
@pytest.mark.parametrize(
"fields", [{"a_string": "cat", "none": (lambda: None), "f": (lambda: "wakka")}]
)
@ -97,6 +102,80 @@ def test_format_prompt_with_func_that_raises(formatter, capsys, xonsh_builtins):
assert "prompt: error" in err
def test_format_prompt_with_no_env(formatter, xonsh_builtins, live_fields):
xonsh_builtins.__xonsh__.shell.prompt_formatter = formatter
env = Env()
env.pop('VIRTUAL_ENV', None) # For virtualenv
env.pop('CONDA_DEFAULT_ENV', None) # For conda/CircleCI
xonsh_builtins.__xonsh__.env = env
assert formatter('{env_name}', fields=live_fields) == ''
@pytest.mark.parametrize('envname', ['env', 'foo', 'bar'])
def test_format_prompt_with_various_envs(formatter, xonsh_builtins, live_fields, envname):
xonsh_builtins.__xonsh__.shell.prompt_formatter = formatter
env = Env(VIRTUAL_ENV=envname)
xonsh_builtins.__xonsh__.env = env
exp = live_fields['env_prefix'] + envname + live_fields['env_postfix']
assert formatter('{env_name}', fields=live_fields) == exp
@pytest.mark.parametrize('pre', ['(', '[[', '', ' '])
@pytest.mark.parametrize('post', [')', ']]', '', ' '])
def test_format_prompt_with_various_prepost(
formatter,
xonsh_builtins,
live_fields,
pre,
post,
):
xonsh_builtins.__xonsh__.shell.prompt_formatter = formatter
env = Env(VIRTUAL_ENV='env')
xonsh_builtins.__xonsh__.env = env
live_fields.update({'env_prefix': pre, 'env_postfix': post})
exp = pre + 'env' + post
assert formatter('{env_name}', fields=live_fields) == exp
def test_noenv_with_disable_set(formatter, xonsh_builtins, live_fields):
xonsh_builtins.__xonsh__.shell.prompt_formatter = formatter
env = Env(VIRTUAL_ENV='env', VIRTUAL_ENV_DISABLE_PROMPT=1)
xonsh_builtins.__xonsh__.env = env
exp = ''
assert formatter('{env_name}', fields=live_fields) == exp
@pytest.mark.parametrize('disable', [0, 1])
def test_custom_env_overrides_default(
formatter,
xonsh_builtins,
live_fields,
disable,
):
xonsh_builtins.__xonsh__.shell.prompt_formatter = formatter
prompt = '!venv active! '
env = Env(
VIRTUAL_ENV='env',
VIRTUAL_ENV_PROMPT=prompt,
VIRTUAL_ENV_DISABLE_PROMPT=disable,
)
xonsh_builtins.__xonsh__.env = env
exp = '' if disable else prompt
assert formatter('{env_name}', fields=live_fields) == exp
def test_promptformatter_cache(formatter):
spam = Mock()
template = "{spam} and {spam}"

View file

@ -13,7 +13,6 @@ import shlex
import signal
import atexit
import pathlib
import platform
import inspect
import warnings
import builtins

View file

@ -23,13 +23,21 @@ def env_name():
``{env_prefix}`` and ``{env_postfix}`` fields.
"""
env_name = find_env_name()
if not env_name:
# no environment, just return
if (
builtins.__xonsh__.env.get("VIRTUAL_ENV_DISABLE_PROMPT")
or not env_name
):
# env name prompt printing disabled, or no environment; just return
return
pf = builtins.__xonsh__.shell.prompt_formatter
pre = pf._get_field_value("env_prefix")
post = pf._get_field_value("env_postfix")
return pre + env_name + post
venv_prompt = builtins.__xonsh__.env.get("VIRTUAL_ENV_PROMPT")
if venv_prompt is not None:
return venv_prompt
else:
pf = builtins.__xonsh__.shell.prompt_formatter
pre = pf._get_field_value("env_prefix")
post = pf._get_field_value("env_postfix")
return pre + env_name + post
def vte_new_tab_cwd():