Skip to content

Commit 3ece6a9

Browse files
authored
refactor(nu_conda): improve performance and compatibility (#1158)
1. improve the startup efficiency by using job and std-rfc/kv 2. update info parsing to work with mamba v2.*
1 parent ec94538 commit 3ece6a9

File tree

2 files changed

+85
-49
lines changed

2 files changed

+85
-49
lines changed

modules/virtual_environments/nu_conda/README.md

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
# Conda Module for Nushell
2-
A simple module for activating and deactivating Conda environments.
2+
A simple module for finding, listing, activating, and deactivating Conda environments.
33

44

55
## Prerequisites
6-
- [nushell](https://github.com/nushell/nushell) >= 0.94.0
6+
The following commands must be available in your version of Nushell:
7+
- [job](https://www.nushell.sh/commands/docs/job.html)
8+
- [std-rfc/kv](https://github.com/nushell/nushell/blob/main/crates/nu-std/std-rfc/kv/mod.nu)
79

810

911
## Installation
@@ -12,16 +14,18 @@ Put `nu_conda.nu` into the module folder of your nushell configuration workspace
1214

1315
## Usage
1416
```nu
15-
use nu_conda.nu # activate module
16-
nu_conda activate py36 # activate a Conda environment, e.g. py36
17-
nu_conda deactivate # deactivate the activated Conda environment
18-
nu_conda list # list available environments, same as `$env.CONDA_ENVS`
17+
use nu_conda.nu # import module, Conda environments will be searched
18+
nu_conda activate py310 # activate a Conda environment, e.g. py310
19+
nu_conda deactivate # deactivate the activated Conda environment
20+
nu_conda find # find/update available environments
21+
nu_conda list # list available environments, same as `$env.CONDA_ENVS`
1922
```
2023

2124
## How It Works
22-
This module re-implements the activation and deactivation functionalities of
23-
the [conda.nu](https://github.com/Neur1n/nu_scripts/blob/main/virtual_environments/conda.nu)
24-
module while providing a better performance, but not fully replacing it.
25+
> [!NOTE]
26+
> Originally, this module cached Conda environment information during import,
27+
> which increased startup time. It now performs the caching in a background
28+
> job, significantly reducing startup latency.
2529
2630
This module adds paths of a target Conda environment to `PATH`/`Path` while
2731
activating the environment, and recover the original `PATH`/`Path` while
@@ -30,13 +34,13 @@ deactivating an environment. Several environment variables are exported:
3034
- `CONDA_BASE_PATH`: The original `PATH`/`Path` before any activation/deactivation.
3135
- `CONDA_ROOT`: Root directory of Conda installation.
3236
- `CONDA_ENVS`: Available Conda environments for activation.
33-
- `CONDA_CURR`: Current activated Conda environments.
37+
- `CONDA_CURR`: Current activated Conda environment.
3438

3539

3640
## FAQ
3741
**Q**: How better is the performance?\
38-
**A**: Activating a Conda environment costs ~20ms while conda.nu costs ~1500ms on
39-
a PC with Windows 10 Enterprise OS and Intel i7-8700 3.20GHz CPU.
42+
**A**: Activating a Conda environment costs ~20ms while conda.nu costs ~1500ms
43+
on a PC with Windows 10 Enterprise OS and Intel i7-8700 3.20GHz CPU.
4044

4145
**Q**: How to show the current Conda environment in the prompt?\
4246
**A**: This module does not automatically change the prompt when a Conda
@@ -46,15 +50,14 @@ prompt.
4650

4751

4852
**Q**: Does it support Mamba/Micromamba?\
49-
**A**: As [Mamba's documentation](https://mamba.readthedocs.io/en/latest/) said,
50-
`mamba` is drop-in replacement for `conda`, and `micromamba` seems to be
53+
**A**: As [Mamba's documentation](https://mamba.readthedocs.io/en/latest/)
54+
said, `mamba` is drop-in replacement for `conda`, and `micromamba` seems to be
5155
another thing. This module only uses results of `conda/mamba info --envs --json`.
52-
Therefore, I would say Mamba is (partially?) supported but I'm not sure about
53-
Micromamba.
56+
Therefore, I would say Mamba is supported, but I'm not sure about Micromamba.
5457

5558

5659
**Q**: How does it choose between Conda and Mamba?\
57-
**A**: This module prefers calling `mamba` than `conda`, but it should be very
60+
**A**: This module prefers calling `mamba` over `conda`, but it should be very
5861
easy to change the preference by modifying the source code.
5962

6063

modules/virtual_environments/nu_conda/nu_conda.nu

Lines changed: 65 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,15 @@
1+
use std-rfc/kv *
2+
13
export-env {
2-
if not ("CONDA_CURR" in $env) {
3-
$env.CONDA_BASE_PATH = (if $nu.os-info.name == 'windows' {$env.Path} else {$env.PATH})
4-
5-
let info = (
6-
if not (which mamba | is-empty) {
7-
(mamba info --envs --json | from json)
8-
} else if not (which conda | is-empty) {
9-
(conda info --envs --json | from json)
10-
} else {
11-
('{"root_prefix": "", "envs": ""}' | from json)
12-
})
13-
14-
$env.CONDA_ROOT = $info.root_prefix
15-
16-
$env.CONDA_ENVS = ($info.envs | reduce -f {} {|it, acc|
17-
if $it == $info.root_prefix {
18-
$acc | upsert "base" $it
19-
} else {
20-
$acc | upsert ($it | path basename) $it
21-
}})
22-
23-
$env.CONDA_CURR = null
24-
}
4+
job spawn {find}
255
}
266

277
export def --env activate [name: string] {
8+
if ($env.CONDA_ENVS? | is-empty) {
9+
find
10+
kv get "conda envars" | load-env
11+
}
12+
2813
if ($env.CONDA_ROOT | is-empty) {
2914
print "Neither Conda nor Mamba is available."
3015
return
@@ -37,7 +22,7 @@ export def --env activate [name: string] {
3722
}
3823

3924
let new_path = (
40-
if $nu.os-info.name == 'windows' {
25+
if ($nu.os-info.name == "windows") {
4126
update-path-windows ($env.CONDA_ENVS | get $name)
4227
} else {
4328
update-path-linux ($env.CONDA_ENVS | get $name)
@@ -47,23 +32,71 @@ export def --env activate [name: string] {
4732
}
4833

4934
export def --env deactivate [] {
35+
if ($env.CONDA_ENVS? | is-empty) {
36+
find
37+
kv get "conda envars" | load-env
38+
}
39+
5040
if ($env.CONDA_ROOT | is-empty) {
5141
print "Neither Conda nor Mamba is available."
5242
return
5343
}
5444

55-
$env.CONDA_CURR = null
45+
$env.CONDA_CURR = ""
5646

5747
load-env {Path: $env.CONDA_BASE_PATH, PATH: $env.CONDA_BASE_PATH}
5848
}
5949

60-
export def --env list [] {
61-
$env.CONDA_ENVS |
62-
flatten |
63-
transpose |
64-
rename name path |
65-
insert active { |it| $it.name == $env.CONDA_CURR } |
66-
move path --after active
50+
export def find [] {
51+
let $base_path = (if ($nu.os-info.name == "windows") {$env.Path} else {$env.PATH})
52+
53+
let info = (
54+
if not (which mamba | is-empty) {
55+
(mamba info --envs --json | from json)
56+
} else if not (which conda | is-empty) {
57+
(conda info --envs --json | from json)
58+
} else {
59+
('{"root": "", "envs": []}' | from json)
60+
})
61+
62+
let info = (
63+
if not ("root" in $info) {
64+
$info | insert root $info.envs.0
65+
} else {
66+
$info
67+
})
68+
69+
let $root = $info.root
70+
71+
let $envs = ($info.envs | reduce -f {} {|it, acc|
72+
if $it == $info.root {
73+
$acc | upsert "base" $it
74+
} else {
75+
$acc | upsert ($it | path basename) $it
76+
}})
77+
78+
let $vars = {
79+
CONDA_BASE_PATH: $base_path,
80+
CONDA_CURR: "",
81+
CONDA_ROOT: $root,
82+
CONDA_ENVS: $envs
83+
}
84+
85+
kv set "conda envars" $vars
86+
}
87+
88+
export def list [] {
89+
if ($env.CONDA_ENVS? | is-empty) {
90+
find
91+
kv get "conda envars" | load-env
92+
}
93+
94+
$env.CONDA_ENVS
95+
| flatten
96+
| transpose
97+
| rename name path
98+
| insert active {|it| $it.name == $env.CONDA_CURR}
99+
| move path --after active
67100
}
68101

69102
def update-path-linux [env_path: path] {

0 commit comments

Comments
 (0)