1

I'm trying to create a make.bat file with functionality similar to a Makefile on a *nix system as part of a cookiecutter project template. The challenge is in figuring out a way to be able to activate a conda environment and have this environment still active when control is passed back to the command prompt.

Here is what the make.bat file looks like. Also, in case you are paying attention, the activate and deactivate commands are not prefixed with source or conda due to the Windows environment.

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: VARIABLES                                                                    :
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

SETLOCAL
SET PROJECT_DIR=%cd%
SET PROJECT_NAME="00_test"
SET ENV_NAME=00_test
SET CONDA_PARENT=arcgispro-py3

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: COMMANDS                                                                     :
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:: Jump to command
GOTO %1

:data
    CALL activate %ENV_NAME%
    CALL python src/data/make_dataset.py
    ECHO ">>> Data processed."
    EXIT /B

:: Export the current environment
:env_export
    CALL conda env export --name %ENV_NAME% > environment.yml
    ECHO ">>> %PROJECT_NAME% conda environment exported to ./environment.yml"
    EXIT /B

:: Build the local environment from the environment file
:env

    :: Run this from the ArcGIS Python Command Prompt
    :: Clone and activate the new environment
    CALL conda create --name %ENV_NAME% --clone %CONDA_PARENT%
    CALL activate %ENV_NAME%

    :: Install additional packages
    CALL conda env update -f environment.yml

    :: Additional steps for the map widget to work in Jupyter Lab
    CALL jupyter labextension install @jupyter-widgets/jupyterlab-manager -y
    CALL jupyter labextension install arcgis-map-ipywidget@1.7.0 -y

    EXIT /B

:: Activate the environment
:env_activate
    CALL activate %ENV_NAME%
    EXIT /B

EXIT /B

I want to simply be able to type...

> make env_activate

...and have the command prompt activate the environment so I can continue working using the project conda environment.

As you can see in the screenshot, while the environment is getting activated, it is not persisting once back at the command prompt.

enter image description here

Any help with this is greatly appreciated. This has been driving me crazy for a long time.

knu2xs
  • 818
  • 2
  • 10
  • 22
  • I note in your image `(00_test) Z:\projects\00_test>EXIT /B` which seems unusual. I can only assume that `CALL activate 00_test` is returning `(00_test)` with just a linefeed, _(Unix style)_, as opposed to a carriage return followed by a line feed, _(Windows style)_. I'm afraid however, that what you've posted is unclear to me, so I cannot assist you with your issue at this time. My only assumption is that you're wanting to set the variables and for them to remain set in the environment after you've used `EXIT`, is that correct, and if so please explain that better. Thank you. – Compo Jan 22 '20 at 02:06
  • I'm using the `EXIT /B` as a way to exit the script execution without exiting the command prompt window. When I didn't have the `/B`, the window would close following any of the commands, which is not what I wanted. – knu2xs Jan 22 '20 at 04:11
  • 1
    @Compo, the `activate` script sets the `prompt` variable by prefixing the prompt with `(00_test)` in this case, to notify the user that the virtual environment is active. Once the `prompt` variable is reset back to the default value later, by use of the `deactivate` script, that indicates that the virtual environment is no longer active. The issue as the image shows, is that the environment change is reset back on the last line as `(00_test)` is absent in the prompt. – michael_heath Jan 22 '20 at 08:50

1 Answers1

1
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: VARIABLES                                                                    :
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

SETLOCAL
SET "PROJECT_DIR=%cd%"
SET "PROJECT_NAME=00_test"
SET "ENV_NAME=00_test"
SET "CONDA_PARENT=arcgispro-py3"

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: COMMANDS                                                                     :
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:: Jump to command
GOTO %1

:data
    ENDLOCAL & (
        CALL activate "%ENV_NAME%"
        CALL python src/data/make_dataset.py
        ECHO ^>^>^> Data processed.
    )
    EXIT /B

:: Export the current environment
:env_export
    ENDLOCAL & (
        CALL conda env export --name "%ENV_NAME%" > environment.yml
        ECHO ^>^>^> "%PROJECT_NAME%" conda environment exported to ./environment.yml
    )
    EXIT /B

:: Build the local environment from the environment file
:env
    ENDLOCAL & (

        REM Run this from the ArcGIS Python Command Prompt
        REM Clone and activate the new environment
        CALL conda create --name "%ENV_NAME%" --clone "%CONDA_PARENT%"
        CALL activate "%ENV_NAME%"

        REM Install additional packages
        CALL conda env update -f environment.yml

        REM Additional steps for the map widget to work in Jupyter Lab
        CALL jupyter labextension install @jupyter-widgets/jupyterlab-manager -y
        CALL jupyter labextension install arcgis-map-ipywidget@1.7.0 -y
    )
    EXIT /B

:: Activate the environment
:env_activate
    ENDLOCAL & CALL activate "%ENV_NAME%"
    EXIT /B

EXIT /B

The problem is that the called batch-file scripts with the environment variables being set, are being unset once the main script ends with an implicit ENDLOCAL, which resets the environment to before the use of SETLOCAL. The activate script needs to be called in a global scope to remain active for use at the command prompt.

Use ENDLOCAL before the the use of CALL, yet in the same block of code to be executed. The % enclosed variables will still be substituted even though the ENDLOCAL has been executed. This should allow the use of SET in the called batch-file scripts to be global if SETLOCAL is not used in those scripts.

I removed the double quotes surrounding some use of ECHO with > and and escape with ^ to become ^>.

Double quotes used at time of use instead of SET time.

Untested as I do not have Anaconda and Jupyter installed.

michael_heath
  • 5,157
  • 2
  • 10
  • 21
  • Thank you so much for the clear explanation of the functioning of `SETLOCAL` and `ENDLOCAL`. This is obviously the part I was missing. Your edits worked perfectly. Also, thank you for pointing out the way to escape characters in the comments as well. While well versed in Python, batch scripting is a little new to me, so I am very grateful for your patience and through explanations. – knu2xs Jan 22 '20 at 18:28