ContinuumIO / anaconda-issues

Anaconda issue tracking
646 stars 220 forks source link

Use PowerShell for Windows' "Anaconda Command Prompt" #311

Open nicktimko opened 9 years ago

nicktimko commented 9 years ago

PowerShell is a more-functional shell to use in lieu of cmd.exe and is available on versions of Windows from XP SP2 and Vista forward.

groutr commented 9 years ago

You can still use Powershell if you wish. However, for support reasons, we still have to support cmd.exe on Windows as the default.

If you add the anaconda scripts directory to the Windows Path environment variable, you should be able to use any shell that you wish as the scripts will be executable system wide.

Please let us know about your experience running anaconda with Powershell.

nicktimko commented 9 years ago

I've used Anaconda from within PowerShell without any problems. My issue comes more from practical, pedagogical concerns: occasionally students in bootcamps/workshops I've taught don't seem to have the Anaconda binaries on their PATH. We also teach PowerShell as a sort of "lie-to-children" because we can talk about the same commands (namely ls) when teaching our Windows users and OS X users.

Anyways, the quick method to get Anaconda working in a shell is to instruct the students to launch the "Anaconda Command Prompt" from the start menu instead of having them edit $env.PATH (arduous). Because it uses cmd.exe instead of PowerShell, some of the facade comes crashing down (ls breaks, need to use dir, etc.)

Granted, for such purposes, it's a bit drastic, but PowerShell has lots of other little niceties anyways. :D

GPhilo commented 6 years ago

I realise this is ages-old, but since then Windows made Powershell the officially recommended shell in Windows. Would it be possible to have some kind of installation switch/flag to use PS instead of cmd (including the start-menu links)? That way, you could leave cmd as default for backwards compatibility and give users the freedom to use a more modern shell if they want to.

LennartPiro commented 6 years ago

+1 for this request. I would like the "Open Terminal" function in Environments view to open a powershell instead of cmd.exe

mingwandroid commented 6 years ago

I would dislike this:

  1. We don't support Powershell very well.
  2. I personally do not want to learn it.
  3. I would prefer to see MSYS2/bash as an option.
chilismaug commented 6 years ago

In 2018, Windows 10 has deprecated CMD.exe as the terminal, you have to hunt for it now. Powershell is the default Windows terminal, so there at least should be an easy option for this to launch when you select "Open Terminal" on Windows.

Garyck91 commented 6 years ago

It all depends on what one is trying to do, but for what it's worth; Linux bash is available on Windows 10

peterquirk commented 6 years ago

PowerShell 6 Core is available on Linux, Mac and Windows. If you want to support a great cross-platform experience, in the spirit of Anaconda and Jupyter, PowerShell Core is a perfect match. See Can we talk about PowerShell Core 6.0 for more info.

BryanWilhite commented 6 years ago

The CMD Anaconda Prompt starts with this command:

%windir%\System32\cmd.exe "/K" C:\tools\Anaconda3\Scripts\activate.bat C:\tools\Anaconda3

The activate.bat script needs to be translated into PowerShell by someone who knows PowerShell and Anaconda:

@REM @ symbols in this file indicate that output should not be printed.
@REM   Setting it this way allows us to not touch the user's echo setting.
@REM   For debugging, remove the @ on the section you need to study.
@setlocal enabledelayedexpansion

@FOR /F "delims=" %%i IN ('@"%~dp0..\python.exe" -c "import ctypes; print(ctypes.cdll.kernel32.GetACP())"') DO @SET "PYTHONIOENCODING=%%i"
@chcp !PYTHONIOENCODING! > NUL

@set "CONDA_NEW_ENV=%~1"
@SET "CONDA_EXE=%~dp0\..\Scripts\conda.exe"

:: this finds either --help or -h and shows the help text
@CALL ECHO "%~1"| @%SystemRoot%\System32\find.exe /I "-h" 1>NUL
@IF NOT ERRORLEVEL 1 (
    @call "%CONDA_EXE%" ..activate "cmd.exe" -h
) else (
    :: reset errorlevel to 0
    cmd /c "exit /b 0"
)

@if "%~2" == "" @goto skiptoomanyargs
    (@echo Error: did not expect more than one argument.) 1>&2
    (@echo     ^(Got %*^)) 1>&2
    @exit /b 1
:skiptoomanyargs

@if not "%~1" == "" @goto skipmissingarg
    @REM Set env to root if no arg provided
    @set CONDA_NEW_ENV=root
:skipmissingarg

@REM Ensure that path or name passed is valid before deactivating anything
@CALL "%CONDA_EXE%" ..checkenv "cmd.exe" "%CONDA_NEW_ENV%"
@IF errorlevel 1 exit /b 1

@REM The argument here tells the deactivate script to leave a placeholder for us when it removes PATH entries,
@REM    so that we can put our new path entries back in the same place
@call "%~dp0\deactivate.bat" "hold"
@if errorlevel 1 exit /b 1

@REM Activate the new environment
@FOR /F "delims=" %%i IN ('@call "%CONDA_EXE%" ..activate "cmd.exe" "%CONDA_NEW_ENV%"') DO @SET "NEW_PATH=%%i"
@IF errorlevel 1 exit /b 1

@REM take a snapshot of pristine state for later
@REM if PROMPT is not set at all, explicitly set it to the default, i.e. current path followed by greater sign
@IF NOT DEFINED PROMPT SET PROMPT=$P$G
@SET "CONDA_PS1_BACKUP=%PROMPT%"
@FOR /F "delims=" %%i IN ('@call "%CONDA_EXE%" ..changeps1') DO @SET "CHANGE_PROMPT=%%i"
@IF errorlevel 1 exit /b 1

:: if our prompt var does not contain reference to CONDA_DEFAULT_ENV, set prompt
@IF "%CHANGE_PROMPT%" == "1" @IF "x%PROMPT:CONDA_DEFAULT_ENV=%" == "x%PROMPT%" (
    SET "PROMPT=(%CONDA_NEW_ENV%) %PROMPT%"
)

@REM always store the full path to the environment, since CONDA_DEFAULT_ENV varies
@FOR /F "tokens=1 delims=;" %%i in ("%NEW_PATH%") DO @SET "CONDA_PREFIX=%%i"

@REM Do we have CONDA_PATH_PLACEHOLDER in PATH?
@SET "CHECK_PLACEHOLDER=import os; print('CONDA_PATH_PLACEHOLDER' in os.environ['PATH'])"
@FOR /F "tokens=1 delims=;" %%i in ('@call "%~dp0\..\python" -c "%CHECK_PLACEHOLDER%"') DO @SET "HAS_PLACEHOLDER=%%i"

@REM look if the deactivate script left a placeholder for us.
@IF "%HAS_PLACEHOLDER%" == "True" (
    @REM If it did, replace it with our NEW_PATH
    @REM    Delayed expansion used here to do replacement with value of NEW_PATH
    @CALL SET "PATH=%%PATH:CONDA_PATH_PLACEHOLDER=!NEW_PATH!%%"
) ELSE (
    @REM If it did not, prepend NEW_PATH
    @SET "PATH=%NEW_PATH%;%PATH%"
)

@REM This persists env variables, which are otherwise local to this script right now.
@endlocal & (
    @REM Used for deactivate, to make sure we restore original state after deactivation
    @SET "CONDA_PS1_BACKUP=%CONDA_PS1_BACKUP%"
    @SET "PROMPT=%PROMPT%"
    @SET "PATH=%PATH%"
    @SET "CONDA_DEFAULT_ENV=%CONDA_NEW_ENV%"
    @SET "CONDA_PREFIX=%CONDA_PREFIX%"

    @REM Run any activate scripts
    @IF EXIST "%CONDA_PREFIX%\etc\conda\activate.d" (
        @PUSHD "%CONDA_PREFIX%\etc\conda\activate.d"
        @FOR %%g in (*.bat) DO @CALL "%%g"
        @POPD
    )
)
quonic commented 6 years ago

Note: First of I'm not a participant of this project. Someone asked for help from the r/Powershell subreddit.

I have something that is half way there, but If someone can provide example output of those CALL's, then I or someone else should be able to create something that would do the job.

jonkyops commented 6 years ago

I don't know anaconda too well, but maybe this can help serve as a starting point for the activate.bat file: https://gist.github.com/jonkyops/98e9f51397eada0f332ace6aafe5227e

Couple things to note:

  1. Noted in the script, but the prompt variable doesn't exist in powershell. Closest thing is a prompt function, but I didn't know how that should be handled for anaconda or if it was even necessary. Anything dealing with changing the prompt is commented out.
  2. It looks like there are other bat files that are being called by activate.bat, those might need to be changed to powershell eventually too.
chrisconlan commented 6 years ago

The r/Powershell subreddit, @pldmgg, and myself have arrived at an almost-complete result as a PowerShell module:

Module Link: https://gist.github.com/pldmgg/8940843fe02f886bc6267a6c66a507ff Instructions Link: https://gist.github.com/pldmgg/c84e802bcecd6e4c962f65be5b5d316d

This module searches for python.exe's in your Anaconda path and asks to select one, and works as a replacement for opening the Anaconda prompt and running activate my-env. The result configures your path similarly to activate.bat, but with a few caveats:

  1. Your python command and all of your Python packages will reflect the virtual environment you selected.
  2. Your conda will be your base conda.exe. It is able to create new environments and install packages, but it can only install packages to the base environment.
  3. pip and easy_install will also only let you install to the base environment.
  4. activate will fail silently by attempting to run activate.bat. This is fine because the PowerShell module aims to replace activate.bat.

So, in a practical sense, you can use this module in its current state to run your Anaconda environments, but not configure them. We are still working on it here and in the r/Powershell subreddit, but I thought I'd share our progress.

pldmgg commented 6 years ago

Hi everyone,

A couple new developments -

Permanent home for the AnacondaEnv Module will be here:

https://github.com/pldmgg/misc-powershell/blob/master/MyModules/AnacondaEnv/AnacondaEnv.psm1

Instructions/Usage examples are still here:

https://gist.github.com/pldmgg/c84e802bcecd6e4c962f65be5b5d316d

I'll try to continue to update it if anyone from Anaconda community would like tweaks, but anyone is free to take it and run with it however they like.

One notable update I just made is the addition of the -Environment parameter. This means that if your particular environment has already been created via...

conda create --name py35 python=3.5

...or similar, you can do...

PS C:\Users\zeroadmin> $SetAnacondaResult = Set-AnacondaEnv -AnacondaDirectoryPath "C:\ProgramData\Anaconda3" -Environment py35
Environment set successfully!

Note, that while conda env list is not updated...

PS C:\Users\zeroadmin> conda env list
# conda environments:
#
base                  *  C:\ProgramData\Anaconda3
py35                     C:\ProgramData\Anaconda3\envs\py35

...you are in fact using the specified version of python...

PS C:\Users\zeroadmin> Get-Command python

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Application     python.exe                                         3.5.515... C:\ProgramData\Anaconda3\envs\py35\python.exe

If anyone thinks there should be additional functionality, or if you would like tweaks to existing functionality, just let me know. Also, please let me know if you run into any issues.

EDIT:

Just wanted to summarize overall workflow and usage -

1) Install Anaconda on Windows

2) Launch Windows PowerShell 5.1 or PowerShell Core 6.X

3) Download AnacondaEnv.psm1 and Import-Module

4) Do initial setup of Anaconda environment in PowerShell via:

$SetAnacondaEnvResult = Set-AnacondaEnv -AnacondaDirectoryPath "C:\ProgramData\Anaconda3"

Now you can use the conda commands.

5) Create an environment like...

conda create --name py35 python=3.5

6) Switch to that environment via...

$SetAnacondaResult = Set-AnacondaEnv -AnacondaDirectoryPath "C:\ProgramData\Anaconda3" -Environment py35
msarahan commented 6 years ago

There's a very long thread and some well-developed options in https://github.com/conda/conda/issues/626#issuecomment-313913036

Powershell support is on our roadmap, and hopefully we'll have something to show soon.