在Windows PowerShell中,workon命令无法激活virtualenv

12
我安装了virtualenvwrapper-win,当我尝试执行这个命令时:
workon <envname>

在CMD中可以正常工作,但在Windows PowerShell中不行。

在Windows PowerShell中,我需要运行Scripts\activate.ps1,然后才能在提示符前获取envname。

请问如何让workon命令在PowerShell中正常工作呢?

7个回答

19

workon是一个批处理脚本。如果你从PowerShell运行它,它会在一个新的CMD子进程中启动,在那里执行它的任务,然后退出并返回到PowerShell提示符。由于子进程不能修改其父进程,当你返回到PowerShell时,所有由workon.bat所做的修改都会丢失。

你基本上有两个选择:

  • 用PowerShell重写workon.bat(以及其他它调用的批处理脚本)。

  • 在不退出CMD子进程的情况下运行workon.bat

  • & cmd /k workon <envname>
    

    如果您只想要一个可以直接从PowerShell调用的workon快捷方式,您可以将该命令行包装在一个函数中,并将函数定义放入您的PowerShell配置文件中:

    如果您只想从PowerShell直接调用workon,可以将该命令行包装在一个函数中,并将函数定义放入您的PowerShell个人资料中:

    function workon($environment) {
      & cmd /k workon.bat $environment
    }
    

    在此处使用带扩展名的脚本名称,以避免无限递归。


1
第二个选项不正确,因为它不再使用PowerShell。本来就可以在第一次使用cmd! - pulsejet

11

Ansgar Wiechers的回答在技术上是可行的,但它使用了cmd,这意味着你基本上是在PowerShell中使用命令提示符,失去了PowerShell提供的额外功能。你可以修改上面的函数如下:

function workon ($env) {
        & .\Envs\$env\Scripts\activate.ps1
}

这将允许您在虚拟环境中继续使用PowerShell命令(在cmd中无法使用,例如ls)。
这也假设您的环境保存在.\Envs中。如果它们在其他地方,则相应地调整函数中的路径,或设置WORKON_HOME环境变量,请参见下文。
如果您已设置WORKON_HOME环境变量(您应该这样做!),则可以改为使用:
function workon ($env) {
        & $env:WORKON_HOME\$env\Scripts\activate.ps1
}

此外,如果您不是Windows用户(像我一样),并且需要帮助确定该函数的位置以及如何在打开PowerShell时加载它。以下是一些帮助我的额外资源:
背景: 如何编写PowerShell脚本模块 导入PowerShell模块 如何让PowerShell在启动时自动加载您的模块: 如何创建PowerShell配置文件 启动已加载模块的PowerShell

默认情况下,您可以安全地使用 $HOME 变量和 "$HOME\Envs$env\Scripts\activate.ps1"。 - userx
1
我只想说这个评论帮助我找到了解决我的问题的方法。谢谢! - ProsperousHeart

4

只需在PowerShell上键入“CMD”,它会打开命令提示符,然后使用“workon”命令。


4

有一个更简单的解决方案!只需转到您的Python脚本文件夹,其中存在workon.bat文件,并创建一个名为workon.ps1的新文件,并将以下行添加到其中

iex ("~\Envs\" + $args[0] + "\Scripts\activate.ps1")

如果您将虚拟环境存储在其他地方,那么您可能需要适当更改此设置,并设置执行策略以允许脚本。现在,您可以在cmd和powershell中使用workon,因为ps1将在powershell中执行,而bat将在cmd中执行。
您还可以查看virtualenvwrapper-win的我的分支(完全披露:我是powershell部分的作者),其中包含一些重写的powershell脚本,并且应该可以在CMD和powershell上工作。如果您想要复制粘贴,请创建两个文件:workon.pscdprojectworkon.ps1:
if (-not (Test-Path env:WORKON_HOME))
{
    $WORKON_HOME = '~\Envs'
} else {
    $WORKON_HOME = ($env:WORKON_HOME).Replace('"','')
}

if (-not (Test-Path env:VIRTUALENVWRAPPER_PROJECT_FILENAME)) {
    $VIRTUALENVWRAPPER_PROJECT_FILENAME = '.project'
} else {
    $VIRTUALENVWRAPPER_PROJECT_FILENAME = ($env:VIRTUALENVWRAPPER_PROJECT_FILENAME).Replace('"','')
}

if ($args.length -eq 0) {
    echo "Pass a name to activate one of the following virtualenvs:"
    echo ==============================================================================
    (Get-ChildItem -Path $WORKON_HOME).Name
    return
}

$VENV = $args[0]

if (!(Test-Path -Path ("$($WORKON_HOME)\$($VENV)"))) {
    echo ("virtualenv $($VENV) does not exist")
    echo "Create it with 'mkvirtualenv $($VENV)'"
    return
}

if (!(Test-Path -Path ("$($WORKON_HOME)\$($VENV)\Scripts\activate.ps1") ))  {
    echo "$($WORKON_HOME)$($VENV)"
    echo "doesn't contain a virtualenv (yet)."
    echo "Create it with 'mkvirtualenv $($VENV)'"
    return
}

iex ("$($WORKON_HOME)\$($VENV)\Scripts\activate.ps1")

if (Test-Path -Path ("$($WORKON_HOME)\$($VENV)\$($VIRTUALENVWRAPPER_PROJECT_FILENAME)")) {
    iex "cdproject"
}

cdproject.ps1:

function Show-Usage {
    echo ""
    echo  "switches to the project dir of the activated virtualenv"
}

if (-not (Test-Path env:VIRTUAL_ENV)) {
    echo ""
    echo "a virtualenv must be activated"
    Show-Usage
    return
}

if (-not (Test-Path env:VIRTUALENVWRAPPER_PROJECT_FILENAME)) {
    $VIRTUALENVWRAPPER_PROJECT_FILENAME = '.project'
} else {
    $VIRTUALENVWRAPPER_PROJECT_FILENAME = ($env:VIRTUALENVWRAPPER_PROJECT_FILENAME).Replace('"','')
}

if (-not (Test-Path "$($env:VIRTUAL_ENV)\$($VIRTUALENVWRAPPER_PROJECT_FILENAME)")) {
    echo ""
    echo "No project directory found for current virtualenv"
    Show-Usage
    return
}


$ENVPRJDIR = Get-Content "$($env:VIRTUAL_ENV)\$($VIRTUALENVWRAPPER_PROJECT_FILENAME)" -First 1

# If path extracted from file contains env variables, the system will not find the path.
# TODO: Add this functionality

cd $ENVPRJDIR

我认为像Ansgar Wiechers所说的键入& cmd /k workon <envname>比你提出的要简单得多。 - ron_g
1
@RonG 我认为该回答的第二部分是错误的,因为它涉及切换到cmd,这样做违背了使用powershell的初衷。我可以同样建议使用cmd,它可以为我完成所有工作... - pulsejet
我相信我的回答已经足够清楚地表明第二个项目符号是一个解决方法,只能从PowerShell启动,但在CMD中运行。此外,在我发布答案时,virtualenv没有PowerShell代码(因此第一个项目符号)。另外,任何使用Invoke-Expression的东西(比如你的代码)都是默认错误的 - Ansgar Wiechers

1

我在Windows10的powershell中使用virtualenvwrapper时遇到了同样的问题。我喜欢@Erock的答案,但是它覆盖了workon,这样运行workon而不带参数会抛出错误,而不是显示可用环境。以下是我的解决方案。

function workon ($env) {
    if ($env) {
        & $env:WORKON_HOME\$env\Scripts\activate.ps1
    } else {
        Write-Host "Pass a name to activate one of the following virtualenvs:"
        Write-Host" ================================================================"
        Get-ChildItem $env:WORKON_HOME -Name
    }
}

请注意,我已经设置了WORKON_HOME环境变量。

0

我也遇到了类似的问题,但是通过按照上面的步骤解决了它。

在这里列出来:

  • 安装 VirtualEnv 和 VirtualEnvWrapper-win
  • 将 ExecutionPolicy 设置为 RemoteSigned Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
  • 将环境变量 Path 'WORKON' 添加到 'envs 目录'
  • 现在尝试 'workon' 命令

0

安装:

{    pip install virtualenvwrapper-win    }

请注意,默认情况下,这些命令只能在CMD中使用。 修改以在PowerShell中使用:
function workon ($env) {
        & .\Envs\$env\Scripts\activate.ps1
 }

创建虚拟环境:

 {    workon venv   }

或任何其他名称 激活中:

 {    . venv\scripts\activate    }

查看已创建的虚拟环境列表:

  {     workon      }

停用:

  {   deactivate      }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接