Как загрузить virtualenv с помощью файла модуля среды (скрипт tcl)?

Я пытаюсь написать файл модуля для программы, которая создает Python virtualenv, Для того, чтобы начать virtualenvнужно сначала запустить /programs/program-env/bin/activate, Как мне сделать это в modulefile? Любая помощь будет оценена.

Примечание: я попытался просто вставить вышеупомянутую строку в файл, и это не сработало.

Спасибо,

Редактировать:

Я пишу файл модуля для загрузки программы, которая может работать только в virtualenv, Обычно эти файлы модулей устанавливают имена переменных и / или добавляют каталог bin в путь. Поскольку вышеупомянутый пакет несколько отличается, я не знаю, как поступить. Пример файла модуля можно найти здесь.

4 ответа

Вот немного более полный ответ, основанный на ответах Donal и betapatch, который позволяет вам переключаться между двумя модулями, которые выполняют похожие действия:

if { [module-info mode load] || [module-info mode switch2] } {
    puts stdout "source /programs/program-env/bin/activate;"
} elseif { [module-info mode remove] && ![module-info mode switch3] } {
    puts stdout "deactivate;"
}

Во-первых, вам нужно использовать source .../activate а не просто .../activate,

Во-вторых, modules есть какая-то ужасная логика, когда swapпинг модули. Если хотите module swap foo bar (Удалить foo и загрузить bar на своем месте) фактически выполняет следующее:

foo: switch1 # prep for remove
foo: remove  # actually remove
bar: switch2 # load new module
foo: switch3 # cleanup
foo: remove  # happens at the same time as foo switch3

Это означает, что если foo а также bar оба модульные файлы используют virtualenvs, второй foo remove будут deactivatebar,

Система Modules довольно странная, поскольку она действительно создает набор инструкций, которые оцениваются вызывающей оболочкой. Это означает, что обычные способы ведения дел Tcl часто не совсем верны; это вызывающий должен бежать /programs/program-env/bin/activate, а не сценарий Tcl.

Первое, что нужно попробовать:

system "/programs/program-env/bin/activate"

Однако, глядя между строк в FAQ, я вижу, что вам, вероятно, потребуется сделать это (с охраной):

if {[module-info mode] == "load"} {
    puts stdout "/programs/program-env/bin/activate"
}

Я понятия не имею, как отменить операцию (которая является частью точки модуля).

Основываясь на ответе Donal Fellows и документах, это можно сделать с помощью:

if { [ module-info mode load ] } {
    puts stdout "/programs/program-env/bin/activate;"
} elseif { [ module-info mode remove ] } {
    puts stdout "deactivate;"
}

Точка с запятой имеет важное значение.

Вы не очень четко объяснили, что вы пытаетесь сделать, но учитывая ваше упоминание сценария tcl в заголовке, я предполагаю, что вы пишете сценарий Tcl, который должен загружать среду virtualenv для манипулирования сценарием python с использованием конфигурации virtualenv. Скрипты активации - это скрипты bash, которые в конечном итоге устанавливают текущую среду. Вы не можете просто отправить их в Tcl, поскольку Tcl не является оболочкой Bourne. Однако вы можете создать подпроцесс оболочки и прочитать его окружение и сравнить его со средой, измененной после выбора сценария активации. Если ваш tcl-скрипт применяет различия к своей среде, результирующий Tcl-процесс будет эквивалентен оболочке bash после выбора сценария активации.

Вот пример. Если вы запустите это как tclsh scriptname bin/activate он печатает среду, которая теперь будет включать дополнительные настройки из сценария активации. В моем тесте на Linux-боксе это добавило переменную VIRTUAL_ENV и изменило PS1 и PATH.

#!/usr/bin/env tclsh
# Load a virtualenv script in a subshell and apply the environment
# changes to the current process environment.

proc read_env {chan varname} {
    upvar #0 $varname E
    set len [gets $chan line]
    if {$len < 0} {
        fileevent $chan readable {}
        set ::completed 1
    } else {
        set pos [string first = $line]
        set key [string range $line 0 [expr {$pos - 1}]]
        set val [string range $line [expr {$pos + 1}] end]
        set E($key) $val
    }
}

proc read_shell_env {varname cmd} {
    set shell [open |[list /bin/bash] "r+"]
    fconfigure $shell -buffering line -encoding utf-8 -blocking 0
    fileevent $shell readable [list read_env $shell $varname]
    puts $shell $cmd
    flush $shell
    vwait ::completed
    close $shell
    return
}

proc update_env {key val} {
    global env
    set env($key) $val
}

proc load_virtualenv {filename} {
    array set ::envA {}
    array set ::envB {}
    read_shell_env ::envA "printenv; exit 0"
    read_shell_env ::envB "source \"$filename\"; printenv; exit 0"

    set keys [lsort [array names ::envA]]
    foreach k [lsort [array names ::envB]] {
        if {[info exists ::envA($k)]} {
            if {$::envA($k) ne $::envB($k)} {
                update_env $k $::envB($k)
            }
        } else {
            update_env $k $::envB($k)
        }
    }
    unset ::envA
    unset ::envB
    return
}

proc main {filename} {
    global env
    load_virtualenv $filename
    foreach key [lsort [array names env]] {
        puts "$key=$env($key)"
    }
    return 0
}

if {!$tcl_interactive} {
    set r [catch [linsert $argv 0 main] err]
    if {$r} {puts stderr $err}
    exit $r
}
Другие вопросы по тегам