Skip to content

Commit

Permalink
Add documentation (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
jaimergp authored Jan 15, 2025
1 parent d8d54c3 commit fedf48d
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 68 deletions.
60 changes: 3 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ Activate conda environments in new shell processes.
## What is this?

This is a replacement subcommand for `conda activate` and `conda deactivate`.
`conda spawn` is a replacement subcommand for the `conda activate` and `conda deactivate` workflow

Instead of writing state to your current shell session, `conda spawn -n ENV-NAME` will spawn a new shell with your activated environment. To deactivate, exit the process with <kbd>Ctrl</kbd>+<kbd>D</kbd>, or run the command `exit`.
Instead of writing state to your current shell session, `conda spawn -n ENV-NAME` will start a new shell with your activated environment. To deactivate, exit the process with <kbd>Ctrl</kbd>+<kbd>D</kbd>, or run the command `exit`.

## Installation

Expand All @@ -20,61 +20,7 @@ This is a `conda` plugin and goes in the `base` environment:
conda install -n base conda-forge::conda-spawn
```

Since it only relies on the `conda` entry point being on `PATH`, you will probably want to remove all the shell initialization stuff from your profiles with:

```bash
conda init --reverse
```

Then, make sure you have added `$CONDA_ROOT/condabin` to your PATH, with `$CONDA_ROOT` being the path to your conda installation. For example, assuming you installed `conda` in `~/conda`, your `~/.bashrc` would need this line:

```bash
export PATH="${PATH}:${HOME}/conda/condabin"
```

On Windows, open the Start Menu and search for "environment variables". You will be able to add the equivalent location (e.g. `C:\Users\username\conda\condabin`) to the `PATH` variable via the UI.

## Why?

The main reasons include:

- Cleaner shell interaction with no need for a `conda` shell function.
- Avoid messing with existing shell processes.
- Faster shell startup when `conda` is not needed.
- Simpler installation and bookkeeping.

## FAQ

### I can't use this in my scripts anymore!

For in-script usage, please consider these replacements for `conda activate`:

For Unix shell scripts:

```bash
eval "$(conda spawn --hook --shell posix -n <ENV-NAME>)"
```

For Windows CMD scripts:

```cmd
FOR /F "tokens=*" %%g IN ('conda spawn --hook --shell cmd -n <ENV-NAME>') do @CALL %%g
```

For Windows Powershell scripts:

```powershell
conda shell.posix activate <ENV-NAME> | Out-String | Invoke-Expression
```

For example, if you want to create a new environment and activate it, it would look like this:

```bash
# Assumes `conda` is in PATH
conda create -n new-env python numpy
eval "$(conda spawn --hook --shell powershell -n new-env)"
python -c "import numpy"
```
More information is available on our [documentation](https://conda-incubator.github.io/conda-spawn).

## Contributing

Expand Down
6 changes: 6 additions & 0 deletions docs/cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# CLI usage

Run `conda spawn --help` for details:

```{program-output} python -m conda spawn --help
```
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"sphinx_design",
"sphinx_copybutton",
"sphinx_reredirects",
"sphinxcontrib.programoutput",
]

myst_heading_anchors = 3
Expand Down
50 changes: 50 additions & 0 deletions docs/howto.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# How-to guides

(shell-cleanup)=
## Clean up your shell initialization logic

Since `conda-spawn` only relies on the `conda` entry point being on `PATH`, you will probably want to remove all the shell initialization stuff from your shell profiles with:

```bash
conda init --reverse
```

Then, make sure you have added `$CONDA_ROOT/condabin` to your PATH, with `$CONDA_ROOT` being the path to your conda installation. For example, assuming you installed `conda` in `~/conda`, your `~/.bashrc` would only need this line:

```bash
export PATH="${PATH}:${HOME}/conda/condabin"
```

On Windows, open the Start Menu and search for "environment variables". You will be able to add the equivalent location (e.g. `C:\Users\username\conda\condabin`) to the `PATH` variable via the UI.

(in-script)=
## Activate an environment inside a shell script

For in-script usage, please consider these replacements for `conda activate`:

For Unix shell scripts:

```bash
eval "$(conda spawn --hook --shell posix -n <ENV-NAME>)"
```

For Windows CMD scripts:

```batch
FOR /F "tokens=*" %%g IN ('conda spawn --hook --shell cmd -n <ENV-NAME>') do @CALL %%g
```

For Windows Powershell scripts:

```powershell
conda spawn --hook --shell powershell -n <ENV-NAME> | Out-String | Invoke-Expression
```

For example, if you want to create a new environment and activate it, it would look like this:

```bash
# Assumes `conda` is in PATH
conda create -n new-env python numpy
eval "$(conda spawn --hook --shell powershell -n new-env)"
python -c "import numpy"
```
26 changes: 16 additions & 10 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# conda-spawn

Welcome to the `conda-spawn` documentation!

`conda spawn` allows you to activate conda environments in new shell processes.


Expand All @@ -15,22 +13,29 @@ We do welcome feedback on what the expected behaviour should have been if someth
:::{grid-item-card} 🏡 Getting started
:link: quickstart
:link-type: doc
New to `conda-spawn`? Start here to learn the essentials
New to `conda spawn`? Start here to learn the essentials
:::

:::{grid-item-card} 💡 Motivation and vision
:link: why
:::{grid-item-card} 📖 How to
:link: howto
:link-type: doc
Read about why `conda-spawn` exists and when you should use it
Quick guides that teach how to leverage `conda spawn`
:::

::::

::::{grid} 2

:::{grid-item-card} 🍱 Features
:link: features
:::{grid-item-card} 🖥️ CLI usage
:link: cli
:link-type: doc
Consult the command-line interface manual
:::

:::{grid-item-card} 💡 Motivation and vision
:link: why
:link-type: doc
Overview of what `conda-spawn` can do for you
Read about why `conda spawn` exists and when you should use it
:::

::::
Expand All @@ -39,6 +44,7 @@ Overview of what `conda-spawn` can do for you
:hidden:
quickstart
howto
cli
why
features
```
63 changes: 63 additions & 0 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Quickstart

## What is this?

`conda spawn` is a replacement subcommand for the `conda activate` and `conda deactivate` workflow.

Instead of writing state to your current shell session, `conda spawn -n ENV-NAME` starts a new shell with your activated environment. To deactivate, exit the process with <kbd>Ctrl</kbd>+<kbd>D</kbd>, or run the command `exit`.

The typical workflow looks like this:

```bash
~ $ which python
python not found
~ $ which conda
/Users/user/Miniforge/condabin/conda
~ $ conda spawn -n base
(base) ~ $ which python
/Users/user/Miniforge/bin/python
(base) ~ $ python my_project.py
working ...
ok!
(base) ~ $ export VAR=1
(base) ~ $ echo $VAR
1
(base) ~ $ exit
~ $ echo $VAR

~ $
```

As you can see, variables set during the `spawn`ed shell session do not leak in the parent session once closed with `exit`. If you have used `poetry shell` or `pixi shell`, this is essentially the same but for `conda`.

## Installation

This is a `conda` plugin and goes in the `base` environment:

```bash
conda install -n base conda-forge::conda-spawn
```

After this, you might want to {ref}`shell-cleanup`.

## Usage

To activate an environment named `my-project`:

```bash
conda spawn -n my-project
```

To deactivate, exit the process with <kbd>Ctrl</kbd>+<kbd>D</kbd>, or run the command `exit`.


## Why?

The main reasons include:

- Cleaner shell interaction with no need for a `conda` shell function.
- Avoid messing with existing shell processes.
- Faster shell startup when `conda` is not needed.
- Simpler installation and bookkeeping.

Do you want to learn more? Head over to {doc}`why`.
24 changes: 24 additions & 0 deletions docs/why.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Motivation and vision

## Motivation

The `conda activate` and `conda deactivate` subcommands were inspired by the `virtualenv` workflow, which implied `source`-ing a shell script shipped in the virtual environment directory. Initially implemented as `source activate` and `source deactivate`, these subcommands were promoted to the `conda` command namespace in [version 4.4.0](https://github.com/conda/conda/blob/main/CHANGELOG.md#440-2017-12-20).

The 4.4.0 activation workflow is still used in `conda` (as of 25.1) and it goes a long way to provide the possibility of modifying the shell session in place. `conda activate` will modify `PATH`, inject a few environment variables and run some activation scripts. Then, `conda deactivate` needs to undo this. That's a lot of work (and code to maintain), specially considering we can accomplish the same thing in an easier way by starting a new shell with the needed modifications and then discarding the process once done. No cleanup necessary!

However, that's not all. In order to provide in-process shell state updates, the `conda` Python entry point needs to be wrapped by a `conda` shell function that intercepts the subcommands and dispatches to either shell subcommands or regular Python subcommands. _Installing_ that shell function cannot be handled by regular Python packaging operations, so a block of code is injected in your shell profile (or platform equivalent). This is what `conda` calls "initialize your shell", as provided in `conda init`.

The `conda` shell function wrapper and the initialization logic have a non-negligible maintenance cost, add testing burden, obfuscate the application model, and, more importantly, complicate the end-user installation in a very invasive way: the shell startup profile needs a block of code to define the `conda` shell function and auto-activation mechanisms. This has a non-negligible cost every time you start a login shell and leaves residual information on uninstalls.

## Vision

This project is inspired by the workflows implemented in `poetry shell` and `pixi shell`. These workflows prove that no shell initialization logic is needed for effective virtual environment management.

The idea is to start new shell processes and then run the activation logic inside them. Once done, the user exits the process and returns to the parent session. This requires no shell function wrapper, which renders all the logic in `conda init` unnecessary; we only need `$CONDA_ROOT/condabin` in `PATH` so we can cleanly find the `conda` entry point.

For now, this idea is distributed as an optional plugin. If proven successful and it's well received by the community, we would propose adding it as a default `conda` plugin and suggest deprecating the old workflow (`conda init`, `activate` and `deactivate`).

## References

- [`poetry shell` plugin](https://github.com/python-poetry/poetry-plugin-shell)
- [conda deep dives: `conda init` and `conda activate`](https://docs.conda.io/projects/conda/en/24.11.x/dev-guide/deep-dives/activation.html)
22 changes: 22 additions & 0 deletions pixi.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ dev = "python -m pip install -e . --no-deps --no-build-isolation"
spawn = "python -m conda spawn"

[tool.pixi.feature.docs.tasks]
docs = { cmd = "sphinx-build -M dirhtml . _build", cwd = "docs" }
docs = { cmd = "python -m sphinx.cmd.build -M dirhtml . _build", cwd = "docs" }
serve = { cmd = "python -m http.server", cwd = "docs/_build/dirhtml" }
clean = { cmd = "rm -rf _build", cwd = "docs" }

Expand All @@ -73,6 +73,7 @@ sphinx-copybutton = "*"
sphinx-design = "*"
sphinx-reredirects = "*"
sphinx-sitemap = "*"
sphinxcontrib-programoutput = "*"

[tool.pixi.feature.test.tasks]
test = 'python -mpytest -vvv'
Expand Down

0 comments on commit fedf48d

Please sign in to comment.