Tutorial

In this tutorial, we will show how to package a simple script with CondaNSIS to make it available on computers without conda installed.

Creating an installer for a script

We want to distribute a script called snake.py, that prints a snake in the terminal for 10 seconds.

import time


SNAKE = r"""
                          ____
 ________________________/ O  \___/
<_____________________________/   \
"""

if __name__ == "__main__":
    print(SNAKE)
    time.sleep(10)

We also define the environment for our script in the conda environment file environment.yml file below.

channels:
  - defaults
dependencies:
  - python

Finally, we write a small script to tell CondaNSIS how to put together the installer.

import os
import condansis

if __name__ == "__main__":
    this_dir = os.path.dirname(__file__)

    # instantiate Installer
    installer = condansis.Installer(
        package_name="snake-simulator",
        package_root=this_dir,
        package_version="0.1",
        include=["snake.py"],
        install_root_package=False,  # do not run pip install in the package root
    )

    # Create a shortcut in the install directory to run
    # $PYTHON $INSTDIR\snake.py
    # where $PYTHON is the path to the interpreter after installation
    installer.add_shortcut(
        shortcut_name=os.path.join("$INSTDIR", "snake.lnk"),
        target_file="$PYTHON",
        parameters=os.path.join("$INSTDIR", "snake.py"),
    )

    # Create the installer
    installer.create()

In this example, we are using 2 special variables:

  • $INSTDIR will be resolved to the full path to the installation directory. This and many other variables are standard in NSIS and can be used to setup installers in CondaNSIS.

  • $PYTHON will be resolved the full path to the python interpreter in the target machine. This is a special variable provided by CondaNSIS.

Additionally, CondaNSIS also provides the variables:

  • $PYTHONW: local pythonw.exe interpreter in target machine.

  • $ENV: Name of conda environment folder in target machine.

The API documentation gives a complete description of the Installer class and add_shortcut method.

Creating an installer for a package

Development of our snake simulator package is coming along and we have now created a nice Python package, sourced an icon, and structured it such as:

package
├── snake
│ ├── __init__.py
│ └── snake.py
├── resources
│ └── snake.ico
├── setup.py
└── environment.yml

When installed using pip or python setup.py, this package creates an entrypoint called snake.exe. We now want to create an installer for our package which will give easy access to this entrypoint. For that, we write the Python script below

from pathlib import Path
import condansis

if __name__ == "__main__":
    this_dir = Path(__file__).parent

    # instantiate Installer
    installer = condansis.Installer(
        package_name="snake-simulator",
        package_root=this_dir,
        package_version="1.0",
        include=["resources"],
        icon=Path("resources", "snake.ico"),
    )

    # Create a shortcut in the snake.exe entrypoint
    # In the target computer, entrypoints can be found at
    # $INSTDIR\$ENV\Scripts
    installer.add_shortcut(
        shortcut_name=Path("$INSTDIR", "snake.lnk"),
        target_file=Path("$INSTDIR", "$ENV", "Scripts", "snake.exe"),
        icon_file=Path("$INSTDIR", "resources", "snake.ico"),
    )

    # Create the installer
    installer.create()

Using Conda-lock files

As an alternative to environment.yml files, CondaNSIS 0.4 added support for conda-lock. To use conda-lock environment files, just define an env_file argument pointing to the .lock file and set conda_command="conda".

"""
This example creates and environment based in a conda-lock file (https://github.com/conda-incubator/conda-lock)
"""

import os
import condansis

if __name__ == "__main__":
    this_dir = os.path.dirname(__file__)

    # instantiate Installer
    installer = condansis.Installer(
        package_name="snake-simulator",
        package_root=this_dir,
        package_version="0.2",
        include=["snake.py"],
        install_root_package=False,  # do not run pip install in the package root
        env_file=os.path.join(this_dir, "conda-win-64.lock"),
        conda_command="conda"  # To use a conda-lock file, we need to overwrite the default ("conda-env")
    )

    # Create a shortcut in the install directory to run
    # $PYTHON $INSTDIR\snake.py
    # where $PYTHON is the path to the interpreter after installation
    installer.add_shortcut(
        shortcut_name=os.path.join("$INSTDIR", "snake.lnk"),
        target_file="$PYTHON",
        parameters=os.path.join("$INSTDIR", "snake.py"),
    )

    # Create the installer
    installer.create()