Merge pull request #3251 from cjrh/vox-activate-absolute-path

vox activate: use absolute path in $PATH
This commit is contained in:
Anthony Scopatz 2019-08-25 13:21:16 -04:00 committed by GitHub
commit dd16d59d86
Failed to generate hash of commit
5 changed files with 84 additions and 8 deletions

View file

@ -2,6 +2,7 @@
branch = true branch = true
source = source =
xonsh/ xonsh/
xontrib/
omit = omit =
*/__amalgam__.py */__amalgam__.py
xonsh/lazyasd.py xonsh/lazyasd.py

View file

@ -207,5 +207,6 @@ Authors are sorted by number of commits.
* chengxuncc * chengxuncc
* goodboy * goodboy
* Atsushi Morimoto * Atsushi Morimoto
* Caleb Hattingh

View file

@ -0,0 +1,24 @@
**Added:**
* <news item>
**Changed:**
* ``vox activate`` will now prepend the absolute path of the virtualenv ``bin/`` directory (or ``Scripts/`` on Windows) to ``$PATH``; before this was a relative path.
**Deprecated:**
* <news item>
**Removed:**
* <news item>
**Fixed:**
* <news item>
**Security:**
* <news item>

View file

@ -1,9 +1,10 @@
"""Vox tests""" """Vox tests"""
import builtins
import stat import stat
import os import os
import subprocess as sp
import pytest import pytest
import sys
from xontrib.voxapi import Vox from xontrib.voxapi import Vox
from tools import skip_if_on_conda, skip_if_on_msys from tools import skip_if_on_conda, skip_if_on_msys
@ -80,6 +81,55 @@ def test_activate(xonsh_builtins, tmpdir):
assert last_event == ("deactivate", "spam") assert last_event == ("deactivate", "spam")
@skip_if_on_msys
@skip_if_on_conda
def test_activate_non_vox_venv(xonsh_builtins, tmpdir):
"""
Create a virtual environment using Python's built-in venv module
(not in VIRTUALENV_HOME) and verify that vox can activate it correctly.
"""
xonsh_builtins.__xonsh__.env.setdefault("PATH", [])
last_event = None
@xonsh_builtins.events.vox_on_activate
def activate(name, path, **_):
nonlocal last_event
last_event = "activate", name, path
@xonsh_builtins.events.vox_on_deactivate
def deactivate(name, path, **_):
nonlocal last_event
last_event = "deactivate", name, path
with tmpdir.as_cwd():
venv_dirname = 'venv'
sp.run([sys.executable, '-m', 'venv', venv_dirname])
vox = Vox()
vox.activate(venv_dirname)
vxv = vox[venv_dirname]
env = xonsh_builtins.__xonsh__.env
assert os.path.isabs(vxv.bin)
assert env["PATH"][0] == vxv.bin
assert os.path.isabs(vxv.env)
assert env["VIRTUAL_ENV"] == vxv.env
assert last_event == (
"activate",
venv_dirname,
str(pathlib.Path(str(tmpdir)) / 'venv')
)
vox.deactivate()
assert not env["PATH"]
assert "VIRTUAL_ENV" not in env
assert last_event == (
"deactivate",
tmpdir.join(venv_dirname),
str(pathlib.Path(str(tmpdir)) / 'venv')
)
@skip_if_on_msys @skip_if_on_msys
@skip_if_on_conda @skip_if_on_conda
def test_path(xonsh_builtins, tmpdir): def test_path(xonsh_builtins, tmpdir):

View file

@ -4,8 +4,8 @@ API for Vox, the Python virtual environment manager for xonsh.
Vox defines several events related to the life cycle of virtual environments: Vox defines several events related to the life cycle of virtual environments:
* ``vox_on_create(env: str) -> None`` * ``vox_on_create(env: str) -> None``
* ``vox_on_activate(env: str) -> None`` * ``vox_on_activate(env: str, path: pathlib.Path) -> None``
* ``vox_on_deactivate(env: str) -> None`` * ``vox_on_deactivate(env: str, path: pathlib.Path) -> None``
* ``vox_on_delete(env: str) -> None`` * ``vox_on_delete(env: str) -> None``
""" """
import os import os
@ -37,7 +37,7 @@ Fired after an environment is created.
events.doc( events.doc(
"vox_on_activate", "vox_on_activate",
""" """
vox_on_activate(env: str) -> None vox_on_activate(env: str, path: pathlib.Path) -> None
Fired after an environment is activated. Fired after an environment is activated.
""", """,
@ -46,7 +46,7 @@ Fired after an environment is activated.
events.doc( events.doc(
"vox_on_deactivate", "vox_on_deactivate",
""" """
vox_on_deactivate(env: str) -> None vox_on_deactivate(env: str, path: pathlib.Path) -> None
Fired after an environment is deactivated. Fired after an environment is deactivated.
""", """,
@ -88,7 +88,7 @@ def _mkvenv(env_dir):
This only cares about the platform. No filesystem calls are made. This only cares about the platform. No filesystem calls are made.
""" """
env_dir = os.path.normpath(env_dir) env_dir = os.path.abspath(env_dir)
if ON_WINDOWS: if ON_WINDOWS:
binname = os.path.join(env_dir, "Scripts") binname = os.path.join(env_dir, "Scripts")
incpath = os.path.join(env_dir, "Include") incpath = os.path.join(env_dir, "Include")
@ -363,7 +363,7 @@ class Vox(collections.abc.Mapping):
if "PYTHONHOME" in env: if "PYTHONHOME" in env:
type(self).oldvars["PYTHONHOME"] = env.pop("PYTHONHOME") type(self).oldvars["PYTHONHOME"] = env.pop("PYTHONHOME")
events.vox_on_activate.fire(name=name) events.vox_on_activate.fire(name=name, path=ve.env)
def deactivate(self): def deactivate(self):
""" """
@ -382,7 +382,7 @@ class Vox(collections.abc.Mapping):
env.pop("VIRTUAL_ENV") env.pop("VIRTUAL_ENV")
events.vox_on_deactivate.fire(name=env_name) events.vox_on_deactivate.fire(name=env_name, path=self[env_name].env)
return env_name return env_name
def __delitem__(self, name): def __delitem__(self, name):