AnnaKozey 发表于 2026-3-17 16:01

Nushell 管理 Python 虚拟环境

最近从 Powershell 转到 Nushell,参考 nu_scripts 中现有的代码,写了个满足自己日常使用习惯的管理 Python 虚拟环境的脚本。(Linux 还是习惯使用 zsh + virtualenvwrapper)


图片.png



```nu
# Developed using nushell v0.111.0
# NOTE: Manually SET path name to PATH on windows to avoid weird bugs!!!
const NU_VENV_VERSION = "1.0.0"
const PATH_NAME = "PATH"

const INFO_STYLE = $'(ansi green)'
const WARN_STYLE = $'(ansi yellow)'
const ERR_STYLE = $'(ansi red)'

# I mainly use nushell on windows.
let is_windows = ($nu.os-info.name == "windows")
let path_sep = (if $is_windows { '\' } else { '/' })
let venv_home = if $is_windows { ($nu.home-dir | path join "Pyvenv") } else { $nu.home-dir | path join ".virtualenvs" }

# Make a new virtualenv using pyvenv
#
@example "mkvenv httpie" {mkvenv httpie} --result r#'
# $HOME/Pyvenv is a soft link here.
Actual environment location may have moved due to redirects, links or junctions.
Requested location: "C:\Users\<YourName>\Pyvenv\http\Scripts\python.exe"
Actual location:    "X:\<RealPath>\Pyvenv\http\Scripts\python.exe'#
export def mkvenv [
name: string # venv name
] {
let new_venv_path = ($venv_home | path join $name)
if ($new_venv_path | path exists) {
    print $"($ERR_STYLE)venv ($name) exists, doing nothing"
    return
}
python -m venv $new_venv_path
}

# List all virtualenvs
#
@example "lsvenv" {lsvenv} --result "
venv1
venv2
venv3"
export def lsvenv [] {
ls $venv_home | where type == dir | each {|d| $d.name | path basename}
}

# Remove venv by name
#
@example "rmvenv httpie" {rmvenv httpie} --result "rm venv dir on venv_home"
export def rmvenv [
name: string # venv name
] {
let venv_path = ($venv_home | path join $name)
let exists = ($venv_path | path exists)
if (not $exists) {
    print $'($WARN_STYLE)($venv_path) not exists, nothing to do'
    return
}

let current_venv = ($env.VIRTUAL_ENV? | default null)
if ($venv_path == $current_venv) {
    print $"($ERR_STYLE)($venv_path) is activated, deactivate it before deletion"
    return
}
rm -r $venv_path
}

def is-string {
($x | describe) == 'string'
}

def has-env {
$name in ($env)
}

# Activate venv
# If no name is specified, all venvs will be printed.
#
@example "workon httpie" {workon httpie} --result "prompt will display activated venv"
export def --env workon [
name?: string # venv name
] {
if ($name | is-empty) {
    return (lsvenv)
}

mut virtual_env = $env.VIRTUAL_ENV? | default null
if $virtual_env != null {
    deactivate
}

$virtual_env = ($venv_home | path join $name)
if (not ($virtual_env | path exists)) {
    print $"($WARN_STYLE)venv ($name) not exists, doing nothing"
    return
}

let bin = (if $is_windows { [$virtual_env, "Scripts"] | path join } else {[$virtual_env, "bin"] | path join})
let virtual_prompt = ""

let old_path = (
    if ($is_windows) and (has-env "Path") {
      $env.Path
    } else {
      $env.PATH
    }
    | if (is-string $in) {
      # if Path/PATH is a string, make it a list
      $in | split row $path_sep | path expand
    } else {
      $in
    }
)

let venv_path = ([$virtual_env $bin] | path join)
# let new_path = ($old_path | prepend $venv_path | str join $path_sep)
let new_path = ($old_path | prepend $venv_path)

# Creating the new prompt for the session
let virtual_prompt = if ($virtual_prompt == '') {
    $'(char lbracket)py:($name)(char rbracket) '
} else {
    ' '
}

let new_env = {
    OLD_PATH: $old_path
    $PATH_NAME: $new_path
    VIRTUAL_ENV: $virtual_env
    VIRTUAL_PROMPT: $virtual_prompt
    # OLD_PROMPT_COMMAND: $old_prompt_command
    # PROMPT_COMMAND    : $new_prompt
    # NU_LIB_DIRS    : $new_lib_dirs
}

# Activate the environment variables
load-env $new_env
}

export def --env deactivate [] {
if ($env.VIRTUAL_ENV? | default null) == null {
    print $"($WARN_STYLE)No venv found, exiting"
    return
}
$env.PATH = $env.OLD_PATH
hide-env OLD_PATH
hide-env VIRTUAL_ENV
hide-env VIRTUAL_PROMPT
}

export alias pydoc = python -m pydoc
export alias pip   = python -m pip

```

Kotoamatsukami 发表于 2026-3-17 21:08

666,这个代码写的真好啊
页: [1]
查看完整版本: Nushell 管理 Python 虚拟环境