workon command doesn't work in Windows PowerShell to activate virtualenv
Asked Answered
S

7

13

I have installed virtualenvwrapper-win and when I try this command

workon <envname>

In CMD it works, but not in Windows PowerShell.

In Windows PowerShell I have to do Scripts\activate.ps1 and then I get the envname before the prompt.

Can you please let me know how can I make workon command working in PowerShell?

Southwesterly answered 14/8, 2016 at 17:3 Comment(0)
B
20

workon is a batch script. If you run it from PowerShell it's launched in a new CMD child process, doing its thing there, then exit and return to the PowerShell prompt. Since child processes can't modify their parent you lose all modifications made by workon.bat when you return to PowerShell.

You basically have two options:

  • Rewrite workon.bat (and the other batch scripts it calls) in PowerShell.

  • Run workon.bat in without exiting from the CMD child process:

    & cmd /k workon <envname>
    

    If you just want a shortcut workon that you can call directly from PowerShell you can wrap that commandline in a function and put the function definition into your PowerShell profile:

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

    Use the scriptname with extension here to avoid infinite recursion.

Bagwig answered 14/8, 2016 at 18:43 Comment(1)
The second option is not right, since it no longer uses powershell. Could have as well used cmd in the first place!Sibyl
B
11

The answer by Ansgar Wiechers technically works but it uses cmd which means you are basically using the cmd prompt from within PowerShell and you lose the additional functionality provided by PowerShell. You can modify the function above to the following:

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

This will allow you to continue to use PowerShell commands (that do not work in cmd such as ls) in your virtual environment

This also assumes that your environments are saved in .\Envs. If they are elsewhere, then adjust the path in the function accordingly, or set the WORKON_HOME environment variable, see below.

If you have set the WORKON_HOME environment variable (which you should !), you can instead use:

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

Additionally, if you are not a Windows user (like me) and need help on where to put that function and how to get it to load when you open PowerShell. Here are some additional resources that helped me:

Background:

How to Write a PowerShell Script Module

Importing a PowerShell Module

How to get PowerShell to autoload your module when it starts:

How to Create a PowerShell Profile

Start PowerShell with modules loaded

Bromley answered 13/12, 2017 at 17:13 Comment(2)
by default, you can go safely with $HOME variable "& $HOME\Envs\$env\Scripts\activate.ps1"Tellurian
I'd just like to say that this comment helped me figure out a solution to my own issue. Thank you!Novosibirsk
S
6

There is a much simpler solution! Just go to your python scripts folder, where the workon.bat file exists and create a new file named workon.ps1 and add the following line to it

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

You many need to change this appropriately if you store your virtualenvs elsewhere and also set the Execution Policy to allow scripts. Now you can use workon in both cmd and powershell, since the ps1 will be executed in powershell and bat in cmd.

You can also check out my fork (full disclosure: I'm the author of the powershell part) of virtualenvwrapper-win, which contains some rewritten scripts for powershell and should work on both CMD and powershell. If you want to copy-paste, create two files, workon.ps and `cdproject.

workon.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
Sibyl answered 2/3, 2018 at 7:33 Comment(3)
I think typing & cmd /k workon <envname> like Ansgar Wiechers said is much simpler than what you're proposingChanson
@RonG I consider the second part of that answer to be wrong, since it involves switching to cmd, defeating the whole point to using powershell. I could have as well suggested using cmd instead, which would do everything for me out of the box ...Sibyl
I believe my answer made sufficiently clear that the second bulletpoint is a workaround that is only launched from PowerShell, but runs in CMD. Besides, at the time my answer was posted there was no PowerShell code for virtualenv (hence the first bulletpoint). And FTR, anything using Invoke-Expression (like your your code) is wrong by default.Bagwig
L
4

just type "CMD" on powershell and it will bring up cmd and then workon

Lombardi answered 14/8, 2020 at 18:31 Comment(0)
B
1

I had the similar issue. Fixed it by following some of the above steps.

Listing it down here:

  • install both VirtualEnv and VirtualEnvWrapper-win
  • Set the ExecutionPolicy to RemoteSigned Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
  • Add environment Path 'WORKON' to 'envs directory'
  • Now try 'workon' command
Balls answered 6/2, 2020 at 20:46 Comment(0)
S
1

I encountered the same problem using virtualenvwrapper in powershell on Windows10. I like the answer by @Erock but that overwrrides the workon in such a way that running workon without an argument throws error instead of showing available environments. Here is my solution.

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
    }
}

Note that I had already set WORKON_HOME envrionment variable.

Shoat answered 14/9, 2020 at 16:9 Comment(0)
D
0

installing:

{    pip install virtualenvwrapper-win    }

Note that the commands at default can only be used in CMD. Modify to use in the powershell:

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

Creating a virtual environment:

 {    workon venv   }

or any other name Activating:

 {    . venv\scripts\activate    }

To see a list of created virtual environments:

  {     workon      }

To deactivate:

  {   deactivate      }
Durston answered 10/10, 2021 at 14:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.