├── test ├── tmp │ └── .gitignore ├── version.bats ├── conda-prefix.bats ├── installer.bats ├── envs.bats ├── virtualenvs.bats ├── delete.bats ├── pip.bats ├── conda.bats ├── hooks.bats ├── init.bats ├── python.bats ├── conda-deactivate.bats ├── test_helper.bash ├── pyvenv.bats ├── prefix.bats ├── virtualenv.bats ├── conda-activate.bats ├── stubs │ └── stub ├── deactivate.bats └── activate.bats ├── .gitignore ├── shims ├── deactivate └── activate ├── etc └── pyenv.d │ ├── rehash │ └── envs.bash │ ├── which │ ├── conda.bash │ ├── python-config.bash │ └── system-site-packages.bash │ └── uninstall │ └── envs.bash ├── .travis.yml ├── .github ├── workflows │ └── tests.yml ├── no-response.yml ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── bin ├── pyenv-deactivate ├── pyenv-activate ├── pyenv-virtualenv-delete ├── pyenv-virtualenvs ├── pyenv-virtualenv-prefix ├── pyenv-virtualenv-init ├── pyenv-sh-deactivate ├── pyenv-sh-activate └── pyenv-virtualenv ├── install.sh ├── MAINTENANCE.md ├── LICENSE ├── libexec └── pyenv-virtualenv-realpath ├── README.md └── CHANGELOG.md /test/tmp/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bats/ 2 | /libexec/pyenv-virtualenv/*/*.class 3 | /libexec/pyenv-virtualenv/*/*.pyc 4 | /libexec/pyenv-virtualenv/*/*.pyo 5 | /libexec/pyenv-virtualenv/*/__pycache__ 6 | *.swo 7 | *.swp 8 | -------------------------------------------------------------------------------- /shims/deactivate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | if [[ "$0" != "${BASH_SOURCE}" ]]; then 3 | eval "$(pyenv sh-deactivate --verbose "$@" || true)" 4 | else 5 | echo "pyenv-virtualenv: deactivate must be sourced. Run 'source deactivate' instead of 'deactivate'" 1>&2 6 | false 7 | fi 8 | -------------------------------------------------------------------------------- /shims/activate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | if [[ "$0" != "${BASH_SOURCE}" ]]; then 3 | eval "$(pyenv sh-activate --verbose "$@" || true)" 4 | else 5 | echo "pyenv-virtualenv: activate must be sourced. Run 'source activate envname' instead of 'activate envname'" 1>&2 6 | false 7 | fi 8 | -------------------------------------------------------------------------------- /etc/pyenv.d/rehash/envs.bash: -------------------------------------------------------------------------------- 1 | virtualenv_list_executable_names() { 2 | local file 3 | shopt -s nullglob 4 | for file in "$PYENV_ROOT"/versions/*/envs/*/bin/*; do 5 | echo "${file##*/}" 6 | done 7 | shopt -u nullglob 8 | } 9 | if declare -f make_shims 1>/dev/null 2>&1; then 10 | make_shims $(virtualenv_list_executable_names | sort -u) 11 | fi 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | install: git clone --depth=1 https://github.com/sstephenson/bats.git 3 | script: bats/bin/bats --tap test 4 | language: c 5 | notifications: 6 | email: 7 | on_success: never 8 | deploy: 9 | provider: releases 10 | api_key: 11 | secure: DsGAt0UmTSGVfsNJ6LmM+LvsV6FYmvX4FcET82XrskPiQW+N8+8JZR8WuZxfmwdJZu+dkkdoq6gYgL2xF7m4LxRG7aw3B5TtbMTrJQeW0hdtCSBwbbYyvwcp2m7ywE8lGAfZQITaGj1R6f2Cgh8cgtcrErjcF0KJsYlVlgNv+/M= 12 | on: 13 | repo: pyenv/pyenv-virtualenv 14 | tags: true 15 | -------------------------------------------------------------------------------- /etc/pyenv.d/which/conda.bash: -------------------------------------------------------------------------------- 1 | # newer versions of conda share programs from the real prefix 2 | # this hook tries to find the executable there 3 | 4 | if [ ! -x "${PYENV_COMMAND_PATH}" ] && [[ "${PYENV_COMMAND_PATH##*/}" == "conda" ]]; then 5 | if [ -d "${PYENV_ROOT}/versions/${version}/conda-meta" ]; then 6 | conda_command_path="$(pyenv-virtualenv-prefix "$version")"/bin/"${PYENV_COMMAND_PATH##*/}" 7 | if [ -x "${conda_command_path}" ]; then 8 | PYENV_COMMAND_PATH="${conda_command_path}" 9 | fi 10 | fi 11 | fi 12 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | on: [pull_request, push] 3 | jobs: 4 | tests: 5 | strategy: 6 | fail-fast: false 7 | matrix: 8 | os: 9 | - ubuntu-24.04 10 | - ubuntu-22.04 11 | - macos-15-intel 12 | - macos-15 13 | - macos-14 14 | runs-on: ${{ matrix.os }} 15 | steps: 16 | - uses: actions/checkout@v2 17 | - run: git clone https://github.com/bats-core/bats-core.git --depth=1 -b v1.10.0 bats 18 | - run: bats/bin/bats --tap test 19 | -------------------------------------------------------------------------------- /bin/pyenv-deactivate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Summary: Deactivate virtual environment 4 | # 5 | # Usage: pyenv deactivate 6 | # 7 | # Deactivate a Python virtual environment. 8 | 9 | set -e 10 | [ -n "$PYENV_DEBUG" ] && set -x 11 | 12 | { printf "\x1B[31;1m" 13 | echo 14 | echo "\`pyenv deactivate' requires Pyenv and Pyenv-Virtualenv to be loaded into your shell." 15 | echo "Check your shell configuration and Pyenv and Pyenv-Virtualenv installation instructions." 16 | echo 17 | printf "\x1B[0m" 18 | } 1>&2 19 | exit 1 20 | -------------------------------------------------------------------------------- /.github/no-response.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-no-response - https://github.com/probot/no-response 2 | 3 | # Number of days of inactivity before an Issue is closed for lack of response 4 | daysUntilClose: 30 5 | # Label requiring a response 6 | responseRequiredLabel: need-feedback 7 | # Comment to post when closing an Issue for lack of response. Set to `false` to disable 8 | closeComment: > 9 | This issue has been automatically closed because there has been no response 10 | to our request for more information from the original author. With only the 11 | information that is currently in the issue, we don't have enough information 12 | to take action. Please reach out if you have or find the answers we need so 13 | that we can investigate further. 14 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [pyenv] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: pyenv # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Usage: PREFIX=/usr/local ./install.sh 3 | # 4 | # Installs pyenv-virtualenv under $PREFIX. 5 | 6 | set -e 7 | 8 | cd "$(dirname "$0")" 9 | 10 | if [ -z "${PREFIX}" ]; then 11 | PREFIX="/usr/local" 12 | fi 13 | 14 | BIN_PATH="${PREFIX}/bin" 15 | LIBEXEC_PATH="${PREFIX}/libexec" 16 | SHIMS_PATH="${PREFIX}/shims" 17 | HOOKS_PATH="${PREFIX}/etc/pyenv.d" 18 | 19 | mkdir -p "$BIN_PATH" 20 | mkdir -p "$LIBEXEC_PATH" 21 | mkdir -p "$SHIMS_PATH" 22 | mkdir -p "$HOOKS_PATH" 23 | 24 | install -p bin/* "$BIN_PATH" 25 | install -p libexec/* "$LIBEXEC_PATH" 26 | install -p shims/* "$SHIMS_PATH" 27 | for hook in etc/pyenv.d/*; do 28 | if [ -d "$hook" ]; then 29 | cp -RPp "$hook" "$HOOKS_PATH" 30 | else 31 | install -p -m 0644 "$hook" "$HOOKS_PATH" 32 | fi 33 | done 34 | -------------------------------------------------------------------------------- /bin/pyenv-activate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Summary: Activate virtual environment 4 | # 5 | # Usage: pyenv activate 6 | # pyenv activate --unset 7 | # 8 | # Activate a Python virtualenv environment in current shell. 9 | # This acts almost as same as `pyenv shell`, but this invokes the `activate` 10 | # script in your shell. 11 | # 12 | # should be a string matching a Python version known to pyenv. 13 | 14 | set -e 15 | [ -n "$PYENV_DEBUG" ] && set -x 16 | 17 | # Provide pyenv completions 18 | if [ "$1" = "--complete" ]; then 19 | echo --unset 20 | exec pyenv-virtualenvs --bare 21 | fi 22 | 23 | { printf "\x1B[31;1m" 24 | echo 25 | echo "\`pyenv activate' requires Pyenv and Pyenv-Virtualenv to be loaded into your shell." 26 | echo "Check your shell configuration and Pyenv and Pyenv-Virtualenv installation instructions." 27 | echo 28 | printf "\x1B[0m" 29 | } 1>&2 30 | exit 1 31 | -------------------------------------------------------------------------------- /MAINTENANCE.md: -------------------------------------------------------------------------------- 1 | Creating a release 2 | ================== 3 | 4 | The release of the new version of Pyenv is done via GitHub Releases. 5 | 6 | Release checklist: 7 | * Start [drafting a new release on GitHub](https://github.com/pyenv/pyenv-virtualenv/releases) to generate a summary of changes. Save the summary locally. 8 | * The summary may need editing. E.g. rephrase entries, delete/merge entries that are too minor or irrelevant to the users (e.g. typo fixes, CI) 9 | * Push the version number in `bin/pyenv-virtualenv` 10 | * Minor version is pushed if there are significant functional changes (not e.g. bugfixes/formula adaptations/supporting niche use cases). 11 | * Major version is pushed if there are breaking changes 12 | * Update `CHANGELOG.md` with the new version number and the edited summary (only the changes section), reformatting it like the rest of the changelog sections 13 | * Commit the changes locally into `master` 14 | * Create a new tag with the new version number and push the changes including the tag 15 | * Create a new release on GitHub based on the tag, using the saved summary -------------------------------------------------------------------------------- /test/version.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | setup() { 6 | export PYENV_ROOT="${TMP}/pyenv" 7 | } 8 | 9 | @test "display virtualenv version" { 10 | setup_virtualenv "2.7.7" 11 | stub pyenv-prefix "echo '${PYENV_ROOT}/versions/2.7.7'" 12 | stub pyenv-version-name "echo 2.7.7" 13 | stub pyenv-exec "python -m venv --help : false" 14 | stub pyenv-exec "virtualenv --version : echo \"1.11\"" 15 | 16 | run pyenv-virtualenv --version 17 | 18 | assert_success 19 | [[ "$output" == "pyenv-virtualenv "?.?.?" (virtualenv 1.11)" ]] 20 | 21 | unstub pyenv-prefix 22 | unstub pyenv-exec 23 | teardown_virtualenv "2.7.7" 24 | } 25 | 26 | @test "display venv version" { 27 | setup_m_venv "3.4.1" 28 | stub pyenv-version-name "echo 3.4.1" 29 | stub pyenv-prefix "echo '${PYENV_ROOT}/versions/3.4.1'" 30 | stub pyenv-exec "python -m venv --help : true" 31 | 32 | run pyenv-virtualenv --version 33 | 34 | assert_success 35 | [[ "$output" == "pyenv-virtualenv "?.?.?" (python -m venv)" ]] 36 | 37 | unstub pyenv-prefix 38 | teardown_m_venv "3.4.1" 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Yamashita, Yuu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the intended use case** 11 | * What your general environment is if it's relevant to the feature request and is not a generic console with a typical Pyenv installation (CI, server with a custom setup, cloud environment, IDE) 12 | * What you are trying to achieve 13 | * What specifically you are doing for that regarding Pyenv 14 | * Where you are stuck 15 | 16 | **Describe the solution you'd like** 17 | A clear and concise description of what you want to happen. 18 | 19 | **Describe alternatives you've considered** 20 | A clear and concise description of any alternative solutions or features you've considered. 21 | [ ] In particular, did you consider [writing a plugin](https://github.com/pyenv/pyenv/blob/master/README.md#pyenv-plugins)? Note that if your plugin has general applicability, you can publish it in the 3rd-party plugin catalog on the Pyenv Wiki as per the link above. 22 | 23 | **Additional context** 24 | Add any other context or screenshots about the feature request here. 25 | -------------------------------------------------------------------------------- /test/conda-prefix.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | setup() { 6 | export PYENV_ROOT="${TMP}/pyenv" 7 | } 8 | 9 | @test "display conda root" { 10 | setup_conda "anaconda-2.3.0" 11 | stub pyenv-version-name "echo anaconda-2.3.0" 12 | stub pyenv-prefix "anaconda-2.3.0 : echo \"${PYENV_ROOT}/versions/anaconda-2.3.0\"" 13 | 14 | PYENV_VERSION="anaconda-2.3.0" run pyenv-virtualenv-prefix 15 | 16 | assert_success 17 | assert_output </dev/null || true)" 15 | REAL_DEFINITION="${REAL_PREFIX#${PYENV_ROOT}/versions/}" 16 | if [[ "${REAL_DEFINITION}" != "${REAL_DEFINITION%/envs/*}" ]]; then 17 | # Uninstall virtualenv by short name 18 | pyenv-virtualenv-delete ${FORCE+-f} "${REAL_DEFINITION}" 19 | fi 20 | else 21 | # Uninstall all virtualenvs inside `envs` directory too 22 | shopt -s nullglob 23 | for virtualenv in "${PREFIX}/envs/"*; do 24 | pyenv-virtualenv-delete ${FORCE+-f} "${DEFINITION}/envs/${virtualenv##*/}" 25 | done 26 | shopt -u nullglob 27 | fi 28 | fi 29 | fi 30 | } 31 | 32 | before_uninstall "uninstall_related_virtual_env" 33 | -------------------------------------------------------------------------------- /libexec/pyenv-virtualenv-realpath: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Summary: Substitute realpath if unavailable as a builtin or file 3 | # Usage: . pyenv-virtualenv-realpath 4 | 5 | if ! { 6 | enable -f "${BASH_SOURCE%/*}"/../../../libexec/pyenv-realpath.dylib realpath || 7 | type realpath 8 | } >/dev/null 2>&1; then 9 | if [ -n "$PYENV_NATIVE_EXT" ]; then 10 | echo "pyenv: failed to load \`realpath' builtin" >&2 11 | exit 1 12 | fi 13 | 14 | READLINK=$(type -p greadlink readlink | head -1) 15 | if [ -z "$READLINK" ]; then 16 | echo "pyenv: cannot find readlink - are you missing GNU coreutils?" >&2 17 | exit 1 18 | fi 19 | 20 | resolve_link() { 21 | $READLINK "$1" 22 | } 23 | 24 | realpath() { 25 | local f="$*" \ 26 | name dir 27 | [[ $f ]] || { 28 | >&2 echo ${FUNCNAME[0]}: missing operand 29 | return 30 | } 31 | while [[ -L $f ]]; do 32 | f="$(resolve_link "$f")" 33 | done 34 | if [[ ! -d $f ]]; then 35 | name="/${f##*/}" 36 | # parent? 37 | dir="${f%/*}" 38 | if [[ $dir == $f ]]; then 39 | #lacks /: parent is current directory 40 | f="$PWD" 41 | else 42 | f="$dir" 43 | fi 44 | fi 45 | #absolute directory 46 | dir="$(cd "$f" 47 | pwd)" 48 | echo "$dir$name" 49 | } 50 | fi 51 | -------------------------------------------------------------------------------- /test/envs.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | setup() { 6 | export PYENV_ROOT="${TMP}/envs/pyenv" 7 | } 8 | 9 | stub_pyenv() { 10 | stub pyenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'" 11 | stub pyenv-hooks "virtualenv : echo" 12 | stub pyenv-rehash " : echo rehashed" 13 | } 14 | 15 | unstub_pyenv() { 16 | unstub pyenv-prefix 17 | unstub pyenv-hooks 18 | unstub pyenv-rehash 19 | } 20 | 21 | @test "path should be handled properly even if there is 'envs' in PYENV_ROOT" { 22 | export PYENV_VERSION="3.5.1" 23 | setup_m_venv "3.5.1" 24 | stub_pyenv "${PYENV_VERSION}" 25 | stub pyenv-version-name "echo '${PYENV_VERSION}'" 26 | stub pyenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'" 27 | stub pyenv-virtualenv-prefix " : false" 28 | stub pyenv-exec "python -m venv --help : true" 29 | stub pyenv-exec "python -m venv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\";mkdir -p \${PYENV_ROOT}/versions/3.5.1/envs/venv/bin" 30 | stub pyenv-exec "python -s -m ensurepip : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\";touch \${PYENV_ROOT}/versions/3.5.1/envs/venv/bin/pip" 31 | 32 | run pyenv-virtualenv venv 33 | 34 | assert_success 35 | assert_output </dev/null | head -1)" 33 | if [ -f "${virtualenv_orig_prefix}" ]; then 34 | virtualenv_prefix="$(cat "${virtualenv_orig_prefix}" 2>/dev/null || true)" 35 | fi 36 | fi 37 | virtualenv_command_path="${virtualenv_prefix}/bin/${PYENV_COMMAND_PATH##*/}" 38 | if [ -x "${virtualenv_command_path}" ]; then 39 | PYENV_COMMAND_PATH="${virtualenv_command_path}" 40 | fi 41 | fi 42 | fi 43 | fi 44 | -------------------------------------------------------------------------------- /test/delete.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | setup() { 6 | export PYENV_ROOT="${TMP}/pyenv" 7 | } 8 | 9 | @test "delete virtualenv" { 10 | mkdir -p "${PYENV_ROOT}/versions/venv27" 11 | 12 | stub pyenv-virtualenv-prefix "venv27 : true" 13 | stub pyenv-rehash "true" 14 | 15 | run pyenv-virtualenv-delete -f "venv27" 16 | 17 | assert_success 18 | 19 | unstub pyenv-virtualenv-prefix 20 | unstub pyenv-rehash 21 | 22 | [ ! -d "${PYENV_ROOT}/versions/venv27" ] 23 | } 24 | 25 | @test "delete virtualenv by symlink" { 26 | mkdir -p "${PYENV_ROOT}/versions/2.7.11/envs/venv27" 27 | ln -fs "${PYENV_ROOT}/versions/2.7.11/envs/venv27" "${PYENV_ROOT}/versions/venv27" 28 | 29 | stub pyenv-rehash "true" 30 | 31 | run pyenv-virtualenv-delete -f "venv27" 32 | 33 | assert_success 34 | 35 | unstub pyenv-rehash 36 | 37 | [ ! -d "${PYENV_ROOT}/versions/2.7.11/envs/venv27" ] 38 | [ ! -L "${PYENV_ROOT}/versions/venv27" ] 39 | } 40 | 41 | @test "delete virtualenv with symlink" { 42 | mkdir -p "${PYENV_ROOT}/versions/2.7.11/envs/venv27" 43 | ln -fs "${PYENV_ROOT}/versions/2.7.11/envs/venv27" "${PYENV_ROOT}/versions/venv27" 44 | 45 | stub pyenv-rehash "true" 46 | 47 | run pyenv-virtualenv-delete -f "2.7.11/envs/venv27" 48 | 49 | assert_success 50 | 51 | unstub pyenv-rehash 52 | 53 | [ ! -d "${PYENV_ROOT}/versions/2.7.11/envs/venv27" ] 54 | [ ! -L "${PYENV_ROOT}/versions/venv27" ] 55 | } 56 | 57 | @test "not delete virtualenv with different symlink" { 58 | mkdir -p "${PYENV_ROOT}/versions/2.7.8/envs/venv27" 59 | mkdir -p "${PYENV_ROOT}/versions/2.7.11/envs/venv27" 60 | ln -fs "${PYENV_ROOT}/versions/2.7.8/envs/venv27" "${PYENV_ROOT}/versions/venv27" 61 | 62 | stub pyenv-rehash "true" 63 | 64 | run pyenv-virtualenv-delete -f "2.7.11/envs/venv27" 65 | 66 | assert_success 67 | 68 | unstub pyenv-rehash 69 | 70 | [ ! -d "${PYENV_ROOT}/versions/2.7.11/envs/venv27" ] 71 | [ -L "${PYENV_ROOT}/versions/venv27" ] 72 | } 73 | 74 | @test "not delete virtualenv with same name" { 75 | mkdir -p "${PYENV_ROOT}/versions/2.7.11/envs/venv27" 76 | mkdir -p "${PYENV_ROOT}/versions/venv27" 77 | 78 | stub pyenv-rehash "true" 79 | 80 | run pyenv-virtualenv-delete -f "2.7.11/envs/venv27" 81 | 82 | assert_success 83 | 84 | unstub pyenv-rehash 85 | 86 | [ ! -d "${PYENV_ROOT}/versions/2.7.11/envs/venv27" ] 87 | [ -d "${PYENV_ROOT}/versions/venv27" ] 88 | } 89 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Prerequisite 11 | * [ ] Make sure no duplicated issue has already been reported in [the pyenv-virtualenv issues](https://github.com/pyenv/pyenv-virtualenv/issues). You should look in closed issues, too. 12 | * [ ] Make sure you are reporting a problem in Pyenv-Virtualenv and not seeking consultation with Pyenv-Virtualenv use. 13 | * GitHub issues are intended mainly for Pyenv-Virtualenv development purposes. If you are seeking help with Pyenv-Virtualenv use, check [Pyenv-Virtualenv documentation](https://github.com/pyenv/pyenv-virtualenv?tab=readme-ov-file#usage), go to a user community site like [Gitter](https://gitter.im/yyuu/pyenv), [StackOverflow](https://stackoverflow.com/questions/tagged/pyenv), etc, or to [Discussions](https://github.com/orgs/pyenv/discussions). 14 | * [ ] Make sure your problem is not derived from packaging (e.g. [Homebrew](https://brew.sh)). 15 | * Please refer to the package documentation for the installation issues, etc. 16 | * [ ] Make sure your problem is not derived from other plugins. 17 | * This repository is maintaining the `pyenv-virtualenv` plugin only. Please refrain from reporting issues of other plugins here. 18 | 19 | ### Describe the bug 20 | A clear and concise description of what the bug is. 21 | Do specify what the expected behaviour is if that's not obvious from the bug's nature. 22 | 23 | #### Reproduction steps 24 | Listing the commands to run in a new console session and their output is usually sufficient. 25 | Please use a Markdown code block (three backticks on a line by themselves before and after the text) to denote a console output excerpt. 26 | 27 | #### Diagnostic details 28 | - [ ] Platform information (e.g. Ubuntu Linux 20.04): 29 | - [ ] OS architecture (e.g. amd64): 30 | - [ ] pyenv version: 31 | - [ ] pyenv-virtualenv version: 32 | - [ ] Python version: 33 | - [ ] virtualenv version (if installed): 34 | - [ ] Please attach the debug log of a faulty Pyenv invocation as a gist 35 | * If the problem happens in a Pyenv invocation, you can turn on debug logging by setting `PYENV_DEBUG=1`, e.g. `env PYENV_DEBUG=1 pyenv install -v 3.6.4` 36 | * If the problem happens outside of a Pyenv invocation, get the debug log like this: 37 | ```bash 38 | # for Bash 39 | export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' 40 | # for Zsh 41 | export PS4='+(%x:%I): %N(%i): ' 42 | 43 | set -x 44 | 45 | set +x 46 | ``` 47 | -------------------------------------------------------------------------------- /etc/pyenv.d/which/system-site-packages.bash: -------------------------------------------------------------------------------- 1 | # if virtualenv is created with `--system-site-packages`, 2 | # looks up executables for source version as well if none is 3 | # installed in the virtualenv. 4 | # https://github.com/yyuu/pyenv-virtualenv/issues/62 5 | 6 | if [ ! -x "${PYENV_COMMAND_PATH}" ]; then 7 | OLDIFS="${IFS}" 8 | IFS=: 9 | version="$(pyenv-version-name)" 10 | IFS="${OLDIFS}" 11 | if [ -f "${PYENV_ROOT}/versions/${version}/bin/activate" ]; then 12 | unset include_system_site_packages 13 | if [ -f "${PYENV_ROOT}/versions/${version}/bin/conda" ]; then 14 | : # do nothing for conda's environments 15 | else 16 | if [ -f "${PYENV_ROOT}/versions/${version}/pyvenv.cfg" ]; then 17 | # venv 18 | virtualenv_binpath="$(cut -b 1-1024 "${PYENV_ROOT}/versions/${version}/pyvenv.cfg" | sed -n '/^ *home *= */s///p' || true)" 19 | virtualenv_prefix="${virtualenv_binpath%/bin}" 20 | if grep -q -i "include-system-site-packages *= *true" "${PYENV_ROOT}/versions/${version}/pyvenv.cfg" 1>/dev/null 2>&1; then 21 | include_system_site_packages=1 22 | fi 23 | else 24 | # virtualenv 25 | if [ -d "${PYENV_ROOT}/versions/${version}/Lib" ]; then 26 | # jython 27 | virtualenv_libpath="${PYENV_ROOT}/versions/${version}/Lib" 28 | else 29 | if [ -d "${PYENV_ROOT}/versions/${version}/lib-python" ]; then 30 | # pypy 31 | virtualenv_libpath="${PYENV_ROOT}/versions/${version}/lib-python" 32 | else 33 | virtualenv_libpath="${PYENV_ROOT}/versions/${version}/lib" 34 | fi 35 | fi 36 | no_global_site_packages="$(find "${virtualenv_libpath}/" -maxdepth 2 -type f -and -name "no-global-site-packages.txt" 2>/dev/null | head -1)" 37 | if [ ! -f "${no_global_site_packages}" ]; then 38 | include_system_site_packages=1 39 | fi 40 | virtualenv_orig_prefix="$(find "${virtualenv_libpath}/" -maxdepth 2 -type f -and -name "orig-prefix.txt" 2>/dev/null | head -1)" 41 | if [ -f "${virtualenv_orig_prefix}" ]; then 42 | virtualenv_prefix="$(cat "${virtualenv_orig_prefix}" 2>/dev/null || true)" 43 | fi 44 | fi 45 | if [ -n "${include_system_site_packages}" ] && [ -n "${virtualenv_prefix}" ]; then 46 | # virtualenv is created with `--system-site-packages` 47 | virtualenv_command_path="${virtualenv_prefix}/bin/${PYENV_COMMAND_PATH##*/}" 48 | if [ -x "${virtualenv_command_path}" ]; then 49 | PYENV_COMMAND_PATH="${virtualenv_command_path}" 50 | fi 51 | fi 52 | fi 53 | fi 54 | fi 55 | -------------------------------------------------------------------------------- /test/pip.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | setup() { 6 | export PYENV_ROOT="${TMP}/pyenv" 7 | } 8 | 9 | stub_pyenv() { 10 | stub pyenv-version-name "echo \${PYENV_VERSION}" 11 | stub pyenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'" 12 | stub pyenv-hooks "virtualenv : echo" 13 | stub pyenv-rehash " : echo rehashed" 14 | } 15 | 16 | unstub_pyenv() { 17 | unstub pyenv-version-name 18 | unstub pyenv-prefix 19 | unstub pyenv-hooks 20 | unstub pyenv-rehash 21 | } 22 | 23 | @test "install pip with ensurepip" { 24 | export PYENV_VERSION="3.5.1" 25 | setup_m_venv "3.5.1" 26 | stub_pyenv "${PYENV_VERSION}" 27 | stub pyenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'" 28 | stub pyenv-virtualenv-prefix " : false" 29 | stub pyenv-exec "python -m venv --help : true" 30 | stub pyenv-exec "python -m venv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\";mkdir -p \${PYENV_ROOT}/versions/3.5.1/envs/venv/bin" 31 | stub pyenv-exec "python -s -m ensurepip : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\";touch \${PYENV_ROOT}/versions/3.5.1/envs/venv/bin/pip" 32 | 33 | run pyenv-virtualenv venv 34 | 35 | assert_success 36 | 37 | assert_output < 6 | # 7 | # -f Attempt to remove the specified virtualenv without prompting 8 | # for confirmation. If the virtualenv does not exist, do not 9 | # display an error message. 10 | # 11 | # See `pyenv virtualenvs` for a complete list of installed versions. 12 | # 13 | set -e 14 | [ -n "$PYENV_DEBUG" ] && set -x 15 | 16 | if [ -z "${PYENV_ROOT}" ]; then 17 | PYENV_ROOT="$(pyenv-root)" 18 | fi 19 | 20 | # Provide pyenv completions 21 | if [ "$1" = "--complete" ]; then 22 | exec pyenv virtualenvs --bare 23 | fi 24 | 25 | resolve_link() { 26 | $(type -p greadlink readlink | head -1) "$1" 27 | } 28 | 29 | usage() { 30 | pyenv-help virtualenv-delete 2>/dev/null 31 | [ -z "$1" ] || exit "$1" 32 | } 33 | 34 | if [ -z "$PYENV_ROOT" ]; then 35 | PYENV_ROOT="${HOME}/.pyenv" 36 | fi 37 | 38 | if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then 39 | usage 0 40 | fi 41 | 42 | unset FORCE 43 | if [ "$1" = "-f" ] || [ "$1" = "--force" ]; then 44 | FORCE=true 45 | shift 46 | fi 47 | 48 | [ "$#" -eq 1 ] || usage 1 >&2 49 | 50 | DEFINITION="$1" 51 | case "$DEFINITION" in 52 | "" | -* ) 53 | usage 1 >&2 54 | ;; 55 | esac 56 | 57 | VERSION_NAME="${DEFINITION##*/}" 58 | # Must initialize because it might be set in the environment 59 | ENV_PREFIX= 60 | ENV_COMPAT_PREFIX="${PYENV_ROOT}/versions/${VERSION_NAME}" 61 | 62 | if [[ "${DEFINITION}" != "${DEFINITION%/envs/*}" ]]; then 63 | ENV_PREFIX="${PYENV_ROOT}/versions/${DEFINITION}" 64 | if [ -L "${ENV_COMPAT_PREFIX}" ]; then 65 | if [[ "${ENV_PREFIX}" != "$(resolve_link "${ENV_COMPAT_PREFIX}" 2>/dev/null || true)" ]]; then 66 | unset ENV_COMPAT_PREFIX 67 | fi 68 | fi 69 | else 70 | if [ -L "${ENV_COMPAT_PREFIX}" ]; then 71 | ENV_PREFIX="$(resolve_link "${ENV_COMPAT_PREFIX}" 2>/dev/null || true)" 72 | if [[ "${ENV_PREFIX%/*/envs/*}" != "${PYENV_ROOT}/versions" ]]; then 73 | echo "pyenv-virtualenv: \`${ENV_COMPAT_PREFIX}' is a symlink for unknown location." 1>&2 74 | exit 1 75 | fi 76 | else 77 | if pyenv-virtualenv-prefix "${VERSION_NAME}" 1>/dev/null 2>&1; then 78 | ENV_PREFIX="${PYENV_ROOT}/versions/${VERSION_NAME}" 79 | unset ENV_COMPAT_PREFIX 80 | elif [ -z "$FORCE" ]; then 81 | echo "pyenv-virtualenv: \`${DEFINITION}' is not a virtualenv." 1>&2 82 | exit 1 83 | fi 84 | fi 85 | fi 86 | 87 | if [ ! -d "$ENV_PREFIX" ]; then 88 | if [ -z "$FORCE" ]; then 89 | echo "pyenv-virtualenv: virtualenv \`$VERSION_NAME' not installed" >&2 90 | exit 1 91 | else 92 | exit 0 93 | fi 94 | fi 95 | 96 | if [ -z "$FORCE" ]; then 97 | read -p "pyenv-virtualenv: remove $ENV_PREFIX? (y/N) " 98 | case "$REPLY" in 99 | y* | Y* ) ;; 100 | * ) exit 1 ;; 101 | esac 102 | fi 103 | 104 | rm -rf "$ENV_PREFIX" 105 | if [ -L "$ENV_COMPAT_PREFIX" ]; then 106 | rm -rf "$ENV_COMPAT_PREFIX" 107 | fi 108 | pyenv-rehash 109 | -------------------------------------------------------------------------------- /bin/pyenv-virtualenvs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Summary: List all Python virtualenvs found in `$PYENV_ROOT/versions/*'. 4 | # Usage: pyenv virtualenvs [--bare] [--skip-aliases] 5 | # 6 | # List all virtualenvs found in `$PYENV_ROOT/versions/*' and its `$PYENV_ROOT/versions/envs/*'. 7 | 8 | set -e 9 | [ -n "$PYENV_DEBUG" ] && set -x 10 | if [ -L "${BASH_SOURCE}" ]; then 11 | READLINK=$(type -p greadlink readlink | head -1) 12 | if [ -z "$READLINK" ]; then 13 | echo "pyenv: cannot find readlink - are you missing GNU coreutils?" >&2 14 | exit 1 15 | fi 16 | resolve_link() { 17 | $READLINK -f "$1" 18 | } 19 | script_path=$(resolve_link ${BASH_SOURCE}) 20 | else 21 | script_path=${BASH_SOURCE} 22 | fi 23 | 24 | . ${script_path%/*}/../libexec/pyenv-virtualenv-realpath 25 | 26 | if [ -z "$PYENV_ROOT" ]; then 27 | PYENV_ROOT="${HOME}/.pyenv" 28 | fi 29 | 30 | unset bare 31 | unset skip_aliases 32 | # Provide pyenv completions 33 | for arg; do 34 | case "$arg" in 35 | --complete ) 36 | echo --bare 37 | echo --skip-aliases 38 | exit ;; 39 | --bare ) bare=1 ;; 40 | --skip-aliases ) skip_aliases=1 ;; 41 | * ) 42 | pyenv-help --usage virtualenvs >&2 43 | exit 1 44 | ;; 45 | esac 46 | done 47 | 48 | versions_dir="${PYENV_ROOT}/versions" 49 | 50 | if [ -d "$versions_dir" ]; then 51 | versions_dir="$(realpath "$versions_dir")" 52 | fi 53 | 54 | if [ -n "$bare" ]; then 55 | hit_prefix="" 56 | miss_prefix="" 57 | current_versions=() 58 | unset print_origin 59 | include_system="" 60 | else 61 | hit_prefix="* " 62 | miss_prefix=" " 63 | OLDIFS="$IFS" 64 | IFS=: current_versions=($(pyenv-version-name || true)) 65 | IFS="$OLDIFS" 66 | print_origin="1" 67 | include_system="" 68 | fi 69 | 70 | num_versions=0 71 | 72 | exists() { 73 | local car="$1" 74 | local cdar 75 | shift 76 | for cdar in "$@"; do 77 | if [ "${car}" == "${cdar}" ]; then 78 | return 0 79 | fi 80 | done 81 | return 1 82 | } 83 | 84 | print_version() { 85 | if exists "$1" "${current_versions[@]}"; then 86 | echo "${hit_prefix}${1}${print_origin+$2}" 87 | else 88 | echo "${miss_prefix}${1}${print_origin+$2}" 89 | fi 90 | num_versions=$((num_versions + 1)) 91 | } 92 | 93 | shopt -s dotglob 94 | shopt -s nullglob 95 | for path in "$versions_dir"/*; do 96 | if [ -d "$path" ]; then 97 | if [ -n "$skip_aliases" ] && [ -L "$path" ]; then 98 | target="$(realpath "$path")" 99 | [ "${target%/*/envs/*}" != "$versions_dir" ] || continue 100 | fi 101 | virtualenv_prefix="$(pyenv-virtualenv-prefix "${path##*/}" 2>/dev/null || true)" 102 | if [ -d "${virtualenv_prefix}" ]; then 103 | print_version "${path##*/}" " (created from ${virtualenv_prefix})" 104 | fi 105 | for venv_path in "${path}/envs/"*; do 106 | venv="${path##*/}/envs/${venv_path##*/}" 107 | virtualenv_prefix="$(pyenv-virtualenv-prefix "${venv}" 2>/dev/null || true)" 108 | if [ -d "${virtualenv_prefix}" ]; then 109 | print_version "${venv}" " (created from ${virtualenv_prefix})" 110 | fi 111 | done 112 | fi 113 | done 114 | shopt -u dotglob 115 | shopt -u nullglob 116 | 117 | if [ "$num_versions" -eq 0 ] && [ -n "$include_system" ]; then 118 | echo "Warning: no Python virtualenv detected on the system" >&2 119 | exit 1 120 | fi 121 | -------------------------------------------------------------------------------- /bin/pyenv-virtualenv-prefix: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Summary: Display real_prefix for a Python virtualenv version 4 | # Usage: pyenv virtualenv-prefix [] 5 | # 6 | 7 | set -e 8 | [ -n "$PYENV_DEBUG" ] && set -x 9 | if [ -L "${BASH_SOURCE}" ]; then 10 | READLINK=$(type -p greadlink readlink | head -1) 11 | if [ -z "$READLINK" ]; then 12 | echo "pyenv: cannot find readlink - are you missing GNU coreutils?" >&2 13 | exit 1 14 | fi 15 | resolve_link() { 16 | $READLINK -f "$1" 17 | } 18 | script_path=$(resolve_link ${BASH_SOURCE}) 19 | else 20 | script_path=${BASH_SOURCE} 21 | fi 22 | 23 | . ${script_path%/*}/../libexec/pyenv-virtualenv-realpath 24 | 25 | if [ -z "$PYENV_ROOT" ]; then 26 | PYENV_ROOT="${HOME}/.pyenv" 27 | fi 28 | 29 | if [ -n "$1" ]; then 30 | versions=($@) 31 | IFS=: PYENV_VERSION="${versions[*]}" 32 | export PYENV_VERSION 33 | else 34 | IFS=: versions=($(pyenv-version-name)) 35 | fi 36 | 37 | append_virtualenv_prefix() { 38 | if [ -d "${VIRTUALENV_PREFIX_PATH}" ]; then 39 | VIRTUALENV_PREFIX_PATHS=("${VIRTUALENV_PREFIX_PATHS[@]}" "${VIRTUALENV_PREFIX_PATH:-${PYENV_PREFIX_PATH}}") 40 | else 41 | echo "pyenv-virtualenv: version \`${version}' is not a virtualenv" 1>&2 42 | exit 1 43 | fi 44 | } 45 | 46 | VIRTUALENV_PREFIX_PATHS=() 47 | for version in "${versions[@]}"; do 48 | if [ "$version" = "system" ]; then 49 | echo "pyenv-virtualenv: version \`${version}' is not a virtualenv" 1>&2 50 | exit 1 51 | fi 52 | PYENV_PREFIX_PATH="$(pyenv-prefix "${version}")" 53 | if [ -x "${PYENV_PREFIX_PATH}/bin/python" ]; then 54 | if [ -f "${PYENV_PREFIX_PATH}/bin/activate" ]; then 55 | if [ -f "${PYENV_PREFIX_PATH}/bin/conda" ]; then 56 | # conda 57 | VIRTUALENV_PREFIX_PATH="${PYENV_PREFIX_PATH}" 58 | else 59 | if [ -f "${PYENV_ROOT}/versions/${version}/pyvenv.cfg" ]; then 60 | # venv 61 | virtualenv_binpath="$(cut -b 1-1024 "${PYENV_ROOT}/versions/${version}/pyvenv.cfg" | sed -n '/^ *home *= */s///p' || true)" 62 | VIRTUALENV_PREFIX_PATH="${virtualenv_binpath%/bin}" 63 | else 64 | # virtualenv 65 | if [ -d "${PYENV_ROOT}/versions/${version}/Lib" ]; then 66 | # jython 67 | virtualenv_libpath="${PYENV_ROOT}/versions/${version}/Lib" 68 | else 69 | if [ -d "${PYENV_ROOT}/versions/${version}/lib-python" ]; then 70 | # pypy 71 | virtualenv_libpath="${PYENV_ROOT}/versions/${version}/lib-python" 72 | else 73 | virtualenv_libpath="${PYENV_ROOT}/versions/${version}/lib" 74 | fi 75 | fi 76 | virtualenv_orig_prefix="$(find "${virtualenv_libpath}/" -maxdepth 2 -type f -and -name "orig-prefix.txt" 2>/dev/null | head -1)" 77 | if [ -f "${virtualenv_orig_prefix}" ]; then 78 | VIRTUALENV_PREFIX_PATH="$(cat "${virtualenv_orig_prefix}" 2>/dev/null || true)" 79 | fi 80 | fi 81 | fi 82 | append_virtualenv_prefix 83 | elif [ -d "${PYENV_PREFIX_PATH}/conda-meta" ]; then 84 | # conda 85 | VIRTUALENV_PREFIX_PATH="$(realpath "${PYENV_PREFIX_PATH}"/../..)" 86 | append_virtualenv_prefix 87 | else 88 | echo "pyenv-virtualenv: version \`${version}' is not a virtualenv" 1>&2 89 | exit 1 90 | fi 91 | else 92 | echo "pyenv-virtualenv: \`python' not found in version \`${version}'" 1>&2 93 | exit 1 94 | fi 95 | done 96 | 97 | IFS=: echo "${VIRTUALENV_PREFIX_PATHS[*]}" 98 | -------------------------------------------------------------------------------- /test/hooks.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | setup() { 6 | export PYENV_ROOT="${TMP}/pyenv" 7 | export HOOK_PATH="${TMP}/i has hooks" 8 | mkdir -p "$HOOK_PATH" 9 | unset PYENV_VIRTUALENV_PROMPT 10 | } 11 | 12 | @test "pyenv-virtualenv hooks" { 13 | cat > "${HOOK_PATH}/virtualenv.bash" < "${HOOK_PATH}/activate.bash" < "${HOOK_PATH}/deactivate.bash" </dev/null 2>&1; then 108 | unset -f deactivate; 109 | fi; 110 | after 111 | EOS 112 | 113 | unstub pyenv-hooks 114 | } 115 | -------------------------------------------------------------------------------- /test/init.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | @test "detect parent shell" { 6 | unset PYENV_SHELL 7 | SHELL=/bin/false run pyenv-virtualenv-init - 8 | assert_success 9 | assert_output_contains ' PROMPT_COMMAND="_pyenv_virtualenv_hook;${PROMPT_COMMAND-}"' 10 | } 11 | 12 | @test "detect parent shell from script (sh)" { 13 | unset PYENV_SHELL 14 | printf '#!/bin/sh\necho "$(pyenv-virtualenv-init -)"' > "${TMP}/script.sh" 15 | chmod +x ${TMP}/script.sh 16 | run ${TMP}/script.sh 17 | assert_success 18 | assert_output_contains_not ' PROMPT_COMMAND="_pyenv_virtualenv_hook;${PROMPT_COMMAND-}"' 19 | rm -f "${TMP}/script.sh" 20 | } 21 | 22 | @test "detect parent shell from script (bash)" { 23 | unset PYENV_SHELL 24 | printf '#!/bin/bash\necho "$(pyenv-virtualenv-init -)"' > "${TMP}/script.sh" 25 | chmod +x ${TMP}/script.sh 26 | run ${TMP}/script.sh 27 | assert_success 28 | assert_output_contains ' PROMPT_COMMAND="_pyenv_virtualenv_hook;${PROMPT_COMMAND-}"' 29 | rm -f "${TMP}/script.sh" 30 | } 31 | 32 | @test "sh-compatible instructions" { 33 | run pyenv-virtualenv-init bash 34 | assert [ "$status" -eq 1 ] 35 | assert_output_contains 'eval "$(pyenv virtualenv-init -)"' 36 | 37 | run pyenv-virtualenv-init zsh 38 | assert [ "$status" -eq 1 ] 39 | assert_output_contains 'eval "$(pyenv virtualenv-init -)"' 40 | } 41 | 42 | @test "fish instructions" { 43 | run pyenv-virtualenv-init fish 44 | assert [ "$status" -eq 1 ] 45 | assert_output_contains 'status --is-interactive; and source (pyenv virtualenv-init -|psub)' 46 | } 47 | 48 | @test "outputs bash-specific syntax" { 49 | export PYENV_VIRTUALENV_ROOT="${TMP}/pyenv/plugins/pyenv-virtualenv" 50 | run pyenv-virtualenv-init - bash 51 | assert_success 52 | assert_output <])" 4 | # 5 | # Automatically activates a Python virtualenv environment based on current 6 | # pyenv version. 7 | # 8 | 9 | set -e 10 | [ -n "$PYENV_DEBUG" ] && set -x 11 | 12 | resolve_link() { 13 | $(type -p greadlink readlink | head -1) "$1" 14 | } 15 | 16 | abs_dirname() { 17 | local cwd="$(pwd)" 18 | local path="$1" 19 | 20 | while [ -n "$path" ]; do 21 | cd "${path%/*}" 22 | local name="${path##*/}" 23 | path="$(resolve_link "$name" || true)" 24 | done 25 | 26 | pwd 27 | cd "$cwd" 28 | } 29 | 30 | PYENV_VIRTUALENV_INSTALL_PREFIX="$(dirname "$(abs_dirname "$0")")" 31 | 32 | print="" 33 | for args in "$@" 34 | do 35 | if [ "$args" = "-" ]; then 36 | print=1 37 | shift 38 | fi 39 | done 40 | 41 | shell="${1:-$PYENV_SHELL}" 42 | if [ -z "$shell" ]; then 43 | shell="$(ps -p "$PPID" -o 'args=' 2>/dev/null || true)" 44 | shell="${shell##-}" 45 | shell="${shell%% *}" 46 | shell="${shell:-$SHELL}" 47 | shell="${shell##*/}" 48 | shell="${shell%%-*}" 49 | fi 50 | 51 | if [ -z "$print" ]; then 52 | case "$shell" in 53 | bash ) 54 | profile='~/.bashrc' 55 | ;; 56 | zsh ) 57 | profile='~/.zshrc' 58 | ;; 59 | ksh ) 60 | profile='~/.profile' 61 | ;; 62 | fish ) 63 | profile='~/.config/fish/config.fish' 64 | ;; 65 | * ) 66 | profile='your profile' 67 | ;; 68 | esac 69 | 70 | { echo "# Load pyenv-virtualenv automatically by adding" 71 | echo "# the following to ${profile}:" 72 | echo 73 | case "$shell" in 74 | fish ) 75 | echo 'status --is-interactive; and source (pyenv virtualenv-init -|psub)' 76 | ;; 77 | * ) 78 | echo 'eval "$(pyenv virtualenv-init -)"' 79 | ;; 80 | esac 81 | echo 82 | } >&2 83 | 84 | exit 1 85 | fi 86 | 87 | case "$shell" in 88 | fish ) 89 | cat </dev/null 2>&1; then 55 | unset -f deactivate; 56 | fi; 57 | EOS 58 | 59 | teardown_conda "anaconda-2.3.0" 60 | } 61 | 62 | @test "deactivate conda root (fish)" { 63 | export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/anaconda-2.3.0" 64 | export VIRTUAL_ENV="${PYENV_ROOT}/versions/anaconda-2.3.0" 65 | export PYENV_ACTIVATE_SHELL= 66 | export CONDA_DEFAULT_ENV="root" 67 | 68 | setup_conda "anaconda-2.3.0" 69 | 70 | PYENV_SHELL="fish" run pyenv-sh-deactivate 71 | 72 | assert_success 73 | assert_output </dev/null 2>&1; then 130 | unset -f deactivate; 131 | fi; 132 | EOS 133 | 134 | teardown_conda "anaconda-2.3.0" "foo" 135 | } 136 | -------------------------------------------------------------------------------- /bin/pyenv-sh-deactivate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Summary: Deactivate virtual environment 4 | # 5 | # Usage: pyenv deactivate 6 | # 7 | # Deactivate a Python virtual environment. 8 | 9 | set -e 10 | [ -n "$PYENV_DEBUG" ] && set -x 11 | 12 | if [ -z "${PYENV_ROOT}" ]; then 13 | PYENV_ROOT="$(pyenv-root)" 14 | fi 15 | 16 | unset FORCE 17 | unset QUIET 18 | 19 | # Define `before_deactivate` and `after_deactivate` functions that allow 20 | # plugin hooks to register a string of code for execution before or 21 | # after deactivating a virtualenv. 22 | declare -a before_hooks after_hooks 23 | 24 | before_deactivate() { 25 | local hook="$1" 26 | before_hooks["${#before_hooks[@]}"]="$hook" 27 | } 28 | 29 | after_deactivate() { 30 | local hook="$1" 31 | after_hooks["${#after_hooks[@]}"]="$hook" 32 | } 33 | 34 | # Load plugin hooks. 35 | OLDIFS="$IFS" 36 | IFS=$'\n' scripts=(`pyenv-hooks deactivate`) 37 | IFS="$OLDIFS" 38 | for script in "${scripts[@]}"; do source "$script"; done 39 | 40 | while [ $# -gt 0 ]; do 41 | case "$1" in 42 | "-f" | "--force" ) 43 | FORCE=1 44 | ;; 45 | "-q" | "--quiet") 46 | QUIET=1 47 | ;; 48 | "-v" | "--verbose" ) 49 | unset QUIET 50 | PYENV_VIRTUALENV_VERBOSE_ACTIVATE=1 51 | ;; 52 | * ) 53 | break 54 | ;; 55 | esac 56 | shift 1 57 | done 58 | 59 | if [ -z "${VIRTUAL_ENV}" ]; then 60 | if [ -z "${FORCE}" ]; then 61 | if [ -z "${QUIET}" ]; then 62 | echo "pyenv-virtualenv: no virtualenv has been activated." 1>&2 63 | fi 64 | echo "false" 65 | exit 1 66 | fi 67 | fi 68 | 69 | shell="$(basename "${PYENV_SHELL:-$SHELL}")" 70 | prefix="${VIRTUAL_ENV}" 71 | 72 | if [[ "${prefix%/*/envs/*}" == "${PYENV_ROOT}/versions" ]]; then 73 | venv="${prefix#${PYENV_ROOT}/versions/}" 74 | else 75 | venv="${prefix##*/}" 76 | fi 77 | 78 | # Execute `before_deactivate` hooks. 79 | for hook in "${before_hooks[@]}"; do eval "$hook"; done 80 | 81 | if [ -n "$PYENV_VIRTUALENV_VERBOSE_ACTIVATE" ]; then 82 | echo "pyenv-virtualenv: deactivate ${venv}" 1>&2 83 | fi 84 | 85 | # conda package anaconda/miniconda scripts (#173) 86 | if [ -d "${prefix}/conda-meta" ] || 87 | [ -x "${prefix}/bin/conda" ]; then 88 | shopt -s nullglob 89 | case "${shell}" in 90 | fish ) 91 | : # conda doesn't support fish 92 | ;; 93 | * ) 94 | for script in "${prefix}/etc/conda/deactivate.d"/*.sh; do 95 | echo ". \"${script}\";" 96 | done 97 | echo "unset CONDA_PREFIX" 98 | ;; 99 | esac 100 | shopt -u nullglob 101 | fi 102 | 103 | if [ -n "${PYENV_ACTIVATE_SHELL}" ]; then 104 | # shell version set in pyenv-sh-activate should be unset 105 | # https://github.com/yyuu/pyenv-virtualenv/issues/61 106 | case "$shell" in 107 | fish ) 108 | cat </dev/null 2>&1; then 221 | unset -f deactivate; 222 | fi; 223 | EOS 224 | ;; 225 | esac 226 | 227 | # Execute `after_deactivate` hooks. 228 | for hook in "${after_hooks[@]}"; do eval "$hook"; done 229 | -------------------------------------------------------------------------------- /test/test_helper.bash: -------------------------------------------------------------------------------- 1 | export TMP="$BATS_TEST_DIRNAME/tmp" 2 | export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' 3 | 4 | PATH=/usr/bin:/usr/sbin:/bin:/sbin 5 | PATH="$BATS_TEST_DIRNAME/../bin:$PATH" 6 | PATH="$TMP/bin:$PATH" 7 | export PATH 8 | 9 | teardown() { 10 | rm -fr "$TMP"/* 11 | } 12 | 13 | stub() { 14 | local FLAG_NO_ORDER= 15 | local FLAG_MULTIPLE= 16 | while (($#)); do 17 | case "$1" in 18 | -N|--no-order) 19 | FLAG_NO_ORDER=1 20 | shift 21 | ;; 22 | -M|--multiple) 23 | FLAG_MULTIPLE=1 24 | shift 25 | ;; 26 | -*) 27 | echo "stub: unrecognized switch: $arg" >$2 28 | return 1 29 | ;; 30 | *) 31 | break 32 | ;; 33 | esac 34 | done 35 | 36 | local FLAGS=- 37 | if [[ -n $FLAG_MULTIPLE ]]; then 38 | FLAGS=M 39 | elif [[ -n $FLAG_NO_ORDER ]]; then 40 | FLAGS=N 41 | fi 42 | 43 | local program="$1" 44 | local prefix="$(echo "$program" | tr a-z- A-Z_)" 45 | shift 46 | 47 | export "${prefix}_STUB_PLAN"="${TMP}/${program}-stub-plan" 48 | export "${prefix}_STUB_RUN"="${TMP}/${program}-stub-run" 49 | export "${prefix}_STUB_LOG"="${TMP}/${program}-stub-log" 50 | export "${prefix}_STUB_END"= 51 | 52 | mkdir -p "${TMP}/bin" 53 | ln -sf "${BATS_TEST_DIRNAME}/stubs/stub" "${TMP}/bin/${program}" 54 | 55 | touch "${TMP}/${program}-stub-plan" 56 | for arg in "$@"; do 57 | echo "$FLAGS" "$arg" >> "${TMP}/${program}-stub-plan" 58 | done 59 | } 60 | 61 | unstub() { 62 | local program="$1" 63 | local prefix="$(echo "$program" | tr a-z- A-Z_)" 64 | local path="${TMP}/bin/${program}" 65 | 66 | export "${prefix}_STUB_END"=1 67 | 68 | local STATUS=0 69 | "$path" || STATUS="$?" 70 | 71 | rm -f "$path" 72 | rm -f "${TMP}/${program}-stub-plan" "${TMP}/${program}-stub-run" 73 | return "$STATUS" 74 | } 75 | 76 | assert() { 77 | if ! "$@"; then 78 | flunk "failed: $@" 79 | fi 80 | } 81 | 82 | flunk() { 83 | { if [ "$#" -eq 0 ]; then cat - 84 | else echo "$@" 85 | fi 86 | } | sed "s:${TMP}:\${TMP}:g" >&2 87 | return 1 88 | } 89 | 90 | assert_success() { 91 | if [ "$status" -ne 0 ]; then 92 | { echo "command failed with exit status $status" 93 | echo "output: $output" 94 | } | flunk 95 | elif [ "$#" -gt 0 ]; then 96 | assert_output "$1" 97 | fi 98 | } 99 | 100 | assert_failure() { 101 | if [ "$status" -eq 0 ]; then 102 | flunk "expected failed exit status" 103 | elif [ "$#" -gt 0 ]; then 104 | assert_output "$1" 105 | fi 106 | } 107 | 108 | assert_equal() { 109 | if [ "$1" != "$2" ]; then 110 | { echo "expected:" 111 | echo "$1" 112 | echo "actual:" 113 | echo "$2" 114 | } | flunk 115 | fi 116 | } 117 | 118 | assert_equal_wildcards() { 119 | if [[ $1 != $2 ]]; then 120 | { echo "expected:" 121 | echo "$2" 122 | echo "actual:" 123 | echo "$1" 124 | } | flunk 125 | fi 126 | } 127 | 128 | assert_output() { 129 | local expected 130 | if [ $# -eq 0 ]; then expected="$(cat -)" 131 | else expected="$1" 132 | fi 133 | assert_equal "$expected" "$output" 134 | } 135 | 136 | assert_output_wildcards() { 137 | local expected 138 | if [ $# -eq 0 ]; then expected="$(cat -)" 139 | else expected="$1" 140 | fi 141 | assert_equal_wildcards "$output" "$expected" 142 | } 143 | 144 | assert_output_contains() { 145 | local expected="$1" 146 | echo "$output" | grep -F "$expected" >/dev/null || { 147 | { echo "expected output to contain $expected" 148 | echo "actual: $output" 149 | } | flunk 150 | } 151 | } 152 | 153 | assert_output_contains_not() { 154 | local expected="$1" 155 | echo "$output" | grep -F "$expected" >/dev/null && { 156 | { echo "expected output to not contain $expected" 157 | echo "actual: $output" 158 | } | flunk; return 159 | } 160 | return 0 161 | } 162 | 163 | create_executable() { 164 | mkdir -p "${PYENV_ROOT}/versions/$1/bin" 165 | touch "${PYENV_ROOT}/versions/$1/bin/$2" 166 | chmod +x "${PYENV_ROOT}/versions/$1/bin/$2" 167 | } 168 | 169 | remove_executable() { 170 | rm -f "${PYENV_ROOT}/versions/$1/bin/$2" 171 | } 172 | 173 | setup_version() { 174 | create_executable "$1" "python" 175 | remove_executable "$1" "activate" 176 | remove_executable "$1" "conda" 177 | } 178 | 179 | teardown_version() { 180 | rm -fr "${PYENV_ROOT}/versions/$1" 181 | } 182 | 183 | setup_virtualenv() { 184 | create_executable "$1" "python" 185 | create_executable "$1" "activate" 186 | remove_executable "$1" "conda" 187 | } 188 | 189 | teardown_virtualenv() { 190 | rm -fr "${PYENV_ROOT}/versions/$1" 191 | } 192 | 193 | setup_m_venv() { 194 | create_executable "$1" "python" 195 | create_executable "$1" "activate" 196 | remove_executable "$1" "conda" 197 | } 198 | 199 | teardown_m_venv() { 200 | rm -fr "${PYENV_ROOT}/versions/$1" 201 | } 202 | 203 | setup_conda() { 204 | create_executable "$1" "python" 205 | create_executable "$1" "activate" 206 | create_executable "$1" "conda" 207 | local conda="$1" 208 | shift 1 209 | local env 210 | for env; do 211 | create_executable "${conda}/envs/${env}" "python" 212 | create_executable "${conda}/envs/${env}" "activate" 213 | create_executable "${conda}/envs/${env}" "conda" 214 | mkdir -p "${PYENV_ROOT}/versions/${conda}/envs/${env}/etc/conda/activate.d" 215 | touch "${PYENV_ROOT}/versions/${conda}/envs/${env}/etc/conda/activate.d/activate.sh" 216 | mkdir -p "${PYENV_ROOT}/versions/${conda}/envs/${env}/etc/conda/deactivate.d" 217 | touch "${PYENV_ROOT}/versions/${conda}/envs/${env}/etc/conda/deactivate.d/deactivate.sh" 218 | done 219 | } 220 | 221 | teardown_conda() { 222 | rm -fr "${PYENV_ROOT}/versions/$1" 223 | } 224 | 225 | -------------------------------------------------------------------------------- /test/pyvenv.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | setup() { 6 | export PYENV_ROOT="${TMP}/pyenv" 7 | } 8 | 9 | stub_pyenv() { 10 | stub pyenv-version-name "echo \${PYENV_VERSION}" 11 | stub pyenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'" 12 | stub pyenv-hooks "virtualenv : echo" 13 | stub pyenv-rehash " : echo rehashed" 14 | } 15 | 16 | unstub_pyenv() { 17 | unstub pyenv-version-name 18 | unstub pyenv-prefix 19 | unstub pyenv-hooks 20 | unstub pyenv-rehash 21 | } 22 | 23 | @test "use venv if virtualenv is not available" { 24 | export PYENV_VERSION="3.5.1" 25 | setup_m_venv "3.5.1" 26 | stub_pyenv "${PYENV_VERSION}" 27 | stub pyenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'" 28 | stub pyenv-virtualenv-prefix " : false" 29 | stub pyenv-exec "python -m venv --help : true" 30 | stub pyenv-exec "python -m venv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\"" 31 | stub pyenv-exec "python -s -m ensurepip : true" 32 | 33 | run pyenv-virtualenv venv 34 | 35 | assert_output < "${PYENV_ROOT}/versions/$1/lib/python${2:-$1}/orig-prefix.txt" 24 | touch "${PYENV_ROOT}/versions/$1/bin/activate" 25 | } 26 | 27 | create_virtualenv_jython() { 28 | create_version "$1" 29 | create_version "${2:-$1}" 30 | mkdir -p "${PYENV_ROOT}/versions/$1/Lib/" 31 | echo "${PYENV_ROOT}/versions/${2:-$1}" > "${PYENV_ROOT}/versions/$1/Lib/orig-prefix.txt" 32 | touch "${PYENV_ROOT}/versions/$1/bin/activate" 33 | } 34 | 35 | create_virtualenv_pypy() { 36 | create_version "$1" 37 | create_version "${2:-$1}" 38 | mkdir -p "${PYENV_ROOT}/versions/$1/lib-python/${2:-$1}" 39 | echo "${PYENV_ROOT}/versions/${2:-$1}" > "${PYENV_ROOT}/versions/$1/lib-python/${2:-$1}/orig-prefix.txt" 40 | touch "${PYENV_ROOT}/versions/$1/bin/activate" 41 | } 42 | 43 | remove_virtualenv() { 44 | remove_version "$1" 45 | remove_version "${2:-$1}" 46 | } 47 | 48 | create_m_venv() { 49 | create_version "$1" 50 | create_version "${2:-$1}" 51 | echo "home = ${PYENV_ROOT}/versions/${2:-$1}/bin" > "${PYENV_ROOT}/versions/$1/pyvenv.cfg" 52 | touch "${PYENV_ROOT}/versions/$1/bin/activate" 53 | } 54 | 55 | remove_m_venv() { 56 | remove_version "${2:-$1}" 57 | } 58 | 59 | create_conda() { 60 | create_version "$1" 61 | create_version "${2:-$1}" 62 | touch "${PYENV_ROOT}/versions/$1/bin/conda" 63 | touch "${PYENV_ROOT}/versions/$1/bin/activate" 64 | mkdir -p "${PYENV_ROOT}/versions/${2:-$1}/bin" 65 | touch "${PYENV_ROOT}/versions/${2:-$1}/bin/conda" 66 | touch "${PYENV_ROOT}/versions/${2:-$1}/bin/activate" 67 | } 68 | 69 | remove_conda() { 70 | remove_version "${2:-$1}" 71 | } 72 | 73 | @test "display prefix of virtualenv created by virtualenv" { 74 | stub pyenv-version-name "echo foo" 75 | stub pyenv-prefix "foo : echo \"${PYENV_ROOT}/versions/foo\"" 76 | create_virtualenv "foo" "2.7.11" 77 | 78 | PYENV_VERSION="foo" run pyenv-virtualenv-prefix 79 | 80 | assert_success 81 | assert_output < 6 | # pyenv activate --unset 7 | # 8 | # Activate a Python virtualenv environment in current shell. 9 | # This acts almost as same as `pyenv shell`, but this invokes the `activate` 10 | # script in your shell. 11 | # 12 | # should be a string matching a Python version known to pyenv. 13 | 14 | set -e 15 | [ -n "$PYENV_DEBUG" ] && set -x 16 | 17 | if [ -z "${PYENV_ROOT}" ]; then 18 | PYENV_ROOT="$(pyenv-root)" 19 | fi 20 | 21 | resolve_link() { 22 | $(type -p greadlink readlink | head -1) "$1" 23 | } 24 | 25 | unset FORCE 26 | unset QUIET 27 | 28 | # Define `before_activate` and `after_activate` functions that allow 29 | # plugin hooks to register a string of code for execution before or 30 | # after activating a virtualenv. 31 | declare -a before_hooks after_hooks 32 | 33 | before_activate() { 34 | local hook="$1" 35 | before_hooks["${#before_hooks[@]}"]="$hook" 36 | } 37 | 38 | after_activate() { 39 | local hook="$1" 40 | after_hooks["${#after_hooks[@]}"]="$hook" 41 | } 42 | 43 | # Load plugin hooks. 44 | OLDIFS="$IFS" 45 | IFS=$'\n' scripts=(`pyenv-hooks activate`) 46 | IFS="$OLDIFS" 47 | for script in "${scripts[@]}"; do source "$script"; done 48 | 49 | while [ $# -gt 0 ]; do 50 | case "$1" in 51 | "--complete" ) 52 | # Provide pyenv completions 53 | echo --unset 54 | exec pyenv-virtualenvs --bare 55 | ;; 56 | "-f" | "--force" ) 57 | FORCE=1 58 | ;; 59 | "-q" | "--quiet" ) 60 | QUIET=1 61 | ;; 62 | "--unset" ) 63 | exec pyenv-sh-deactivate 64 | ;; 65 | "-v" | "--verbose" ) 66 | unset QUIET 67 | PYENV_VIRTUALENV_VERBOSE_ACTIVATE=1 68 | ;; 69 | * ) 70 | break 71 | ;; 72 | esac 73 | shift 1 74 | done 75 | 76 | get_current_versions() { 77 | local IFS=: 78 | current_versions=($(pyenv-version-name 2>/dev/null)) 79 | } 80 | 81 | no_shell= 82 | versions=("$@") 83 | current_versions=() 84 | if [ -z "${versions}" ]; then 85 | no_shell=1 86 | get_current_versions 87 | versions=("${current_versions[@]}") 88 | fi 89 | 90 | if [ -z "${PYENV_VIRTUALENV_INIT}" ]; then 91 | # Backward compatibility issue 92 | # https://github.com/yyuu/pyenv-virtualenv/issues/26 93 | no_shell= 94 | fi 95 | 96 | venv="${versions}" 97 | 98 | if [ -n "${VIRTUAL_ENV}" ]; then 99 | # exit as success if a non-pyenv virtualenv is active 100 | if [[ -z $PYENV_VIRTUAL_ENV || $PYENV_VIRTUAL_ENV != "$VIRTUAL_ENV" ]]; then 101 | if [ -z "${FORCE}" ]; then 102 | if [ -z "${QUIET}" ]; then 103 | echo "pyenv-virtualenv: virtualenv \`${VIRTUAL_ENV}' is already activated" 1>&2 104 | fi 105 | echo "true" 106 | exit 0 107 | fi 108 | fi 109 | fi 110 | 111 | if ! pyenv-virtualenv-prefix "${venv}" 1>/dev/null 2>&1; then 112 | # fallback to virtualenv of current version 113 | [ -n "${current_versions}" ] || get_current_versions 114 | new_venv="${current_versions%/envs/*}/envs/${venv}" 115 | if pyenv-virtualenv-prefix "${new_venv}" 1>/dev/null 2>&1; then 116 | venv="${new_venv}" 117 | versions[0]="${new_venv}" 118 | else 119 | if [ -z "${QUIET}" ]; then 120 | echo "pyenv-virtualenv: version \`${venv}' is not a virtualenv" 1>&2 121 | fi 122 | echo "false" 123 | exit 1 124 | fi 125 | fi 126 | 127 | # exit as error if there are multiple virtualenvs 128 | # https://github.com/yyuu/pyenv-virtualenv/issues/105 129 | for version in "${versions[@]}"; do 130 | if [[ "${version}" != "${venv}" ]]; then 131 | if pyenv-virtualenv-prefix "${version}" 1>/dev/null 2>&1; then 132 | if [ -z "${QUIET}" ]; then 133 | echo "pyenv-virtualenv: cannot activate multiple versions at once: ${versions[@]}" 1>&2 134 | fi 135 | echo "false" 136 | exit 1 137 | fi 138 | fi 139 | done 140 | 141 | shell="${PYENV_SHELL:-${SHELL##*/}}" 142 | prefix="$(pyenv-prefix "${venv}")" 143 | 144 | if [ -L "${prefix}" ]; then 145 | prefix="$(resolve_link "${prefix}" 2>/dev/null)" 146 | fi 147 | 148 | # exit as success if the virtualenv is already activated 149 | if [[ "${VIRTUAL_ENV}" == "${prefix}" ]]; then 150 | if [ -z "${FORCE}" ]; then 151 | if [ -z "${QUIET}" ]; then 152 | echo "pyenv-virtualenv: version \`${venv}' is already activated" 1>&2 153 | fi 154 | echo "true" 155 | exit 0 156 | fi 157 | fi 158 | 159 | pyenv-sh-deactivate --force --quiet || true 160 | 161 | # Execute `before_activate` hooks. 162 | for hook in "${before_hooks[@]}"; do eval "$hook"; done 163 | 164 | if [ -n "$PYENV_VIRTUALENV_VERBOSE_ACTIVATE" ]; then 165 | echo "pyenv-virtualenv: activate ${venv}" 1>&2 166 | fi 167 | 168 | if [ -z "$no_shell" ]; then 169 | # shell version set in pyenv-sh-activate should be unset 170 | # https://github.com/yyuu/pyenv-virtualenv/issues/61 171 | OLDIFS="$IFS" 172 | IFS=: 173 | case "$shell" in 174 | fish ) 175 | cat <"$STUB_LOCKFILE" ) 2>/dev/null && acquired=1 39 | 40 | if [[ -n $acquired ]]; then 41 | trap release_lock EXIT 42 | break 43 | else 44 | # POSIX sleep(1) doesn't provide subsecond precision, but many others do 45 | sleep 0.1 2>/dev/null || sleep 1 46 | fi 47 | done 48 | if [[ -z $acquired ]]; then 49 | echo "$0: error: could not acquire stub lock \`$STUB_LOCKFILE' in ${acquire_timeout} seconds" >&2 50 | exit 2 51 | fi 52 | } 53 | 54 | acquire_lock 55 | 56 | if [[ -z $STUB_END ]]; then echo "$program" "$@" >>"$STUB_LOG"; fi 57 | 58 | [[ -e $STUB_PLAN ]] || exit 1 59 | 60 | # Initialize or load the stub run information. 61 | read_runfile() { 62 | if [[ -e $STUB_RUN ]]; then source "$STUB_RUN"; fi 63 | } 64 | write_runfile() { 65 | { 66 | local i 67 | echo "STUB_INDEX=$STUB_INDEX" 68 | echo "STUB_RESULT=$STUB_RESULT" 69 | echo "STUB_RUNCOUNTS=()" 70 | for i in ${!STUB_RUNCOUNTS[@]}; do 71 | echo "STUB_RUNCOUNTS[$i]=${STUB_RUNCOUNTS[$i]}" 72 | done 73 | } > "$STUB_RUN" 74 | } 75 | update_runfile_index() { 76 | ( STUB_INDEX=$((STUB_INDEX + 1)) 77 | write_runfile 78 | ) 79 | } 80 | update_runfile_result() { 81 | ( 82 | # Another stubs may have run while we were running payload 83 | # So we need to merge possible state changes 84 | local our_result="$STUB_RESULT" 85 | local -a our_runcounts 86 | array_copy STUB_RUNCOUNTS our_runcounts 87 | 88 | read_runfile 89 | 90 | # merge our match_result and their match_result, with failure taking precedence 91 | STUB_RESULT=$(( our_result | STUB_RESULT )) 92 | 93 | # 3-way merge STUB_RUNCOUNTS (their changes), 94 | # our_runcounts (our changes) and initial_runcounts (base) 95 | local i 96 | for i in $(printf '%s\n' ${!STUB_RUNCOUNTS[@]} ${!our_runcounts[@]} | sort -u); do 97 | STUB_RUNCOUNTS[$i]=$((STUB_RUNCOUNTS[i] + our_runcounts[i] - initial_runcounts[i])) 98 | done 99 | 100 | write_runfile 101 | ) 102 | } 103 | 104 | array_copy() { 105 | #`declare -p' is supposed to produce "declare -a src=([index]="value" )" 106 | local data="$(declare -p ${1:?})" 107 | local dest="${2:?}" 108 | # Bash 5 dumps empty arrays as "declare -a arr" 109 | if [[ $data != *=* ]]; then 110 | data="()"; 111 | else 112 | data="${data#*=}" 113 | fi 114 | 115 | # Bash 3 and MacPorts version of Bash 5 dump arrays in single quotes "declare -a arr='()'" 116 | # but arr='()' createss "([0]='')" rather than duplicate the array 117 | if [[ ${data:0:1} == "'" && ${data:${#data}-1:1} == "'" ]]; then 118 | data="${data:1:${#data}-2}" 119 | fi 120 | eval "$dest=$data" 121 | } 122 | 123 | STUB_INDEX=1 124 | STUB_RESULT=0 125 | declare -a STUB_RUNCOUNTS 126 | read_runfile 127 | declare -a initial_runcounts 128 | array_copy STUB_RUNCOUNTS initial_runcounts 129 | 130 | # ${PROGRAM}_STUB_END envvar is set externally to trigger verification mode for `unstub' 131 | # Execution mode 132 | if [[ -z $STUB_END ]]; then 133 | 134 | # Loop over each line in the plan. 135 | regular_command_index=0 136 | no_order_command_index=0 137 | match_result=1 138 | while IFS= read -r line; do 139 | line_flags="${line%% *}" 140 | line="${line#${line_flags} }" 141 | line_flag_no_order="$(if [[ $line_flags == N ]]; then echo 1; fi)" 142 | line_flag_multiple="$(if [[ $line_flags == M ]]; then echo 1; fi)" 143 | line_flag_regular="$(if [[ $line_flags == - ]]; then echo 1; fi)" 144 | unset line_flags 145 | 146 | # Go through the plan until a match is found. 147 | # For regular commands, only check the next command by index. 148 | # Also keep track of no-order commands for the purpose of run count tracking 149 | if [[ -n $line_flag_regular ]]; then 150 | regular_command_index=$(($regular_command_index + 1)) 151 | if [[ $regular_command_index -ne $STUB_INDEX ]]; then 152 | continue; 153 | fi 154 | else 155 | no_order_command_index=$(($no_order_command_index + 1)) 156 | fi 157 | 158 | # Split the line into an array of arguments to 159 | # match and a command to run to produce output. 160 | command=" $line" 161 | if [[ $command == *" : "* ]]; then 162 | patterns="${command%% : *}" 163 | command="${command#* : }" 164 | fi 165 | 166 | # Naively split patterns by whitespace for now. 167 | # In the future, use a sed script to split while 168 | # respecting quoting. 169 | set -f 170 | patterns=($patterns) 171 | set +f 172 | arguments=("$@") 173 | 174 | # Match the expected argument patterns to actual 175 | # arguments. 176 | match_result=0 177 | for (( i=0; i<${#patterns[@]}; i++ )); do 178 | pattern="${patterns[$i]}" 179 | argument="${arguments[$i]}" 180 | 181 | case "$argument" in 182 | $pattern ) ;; 183 | * ) match_result=1 ;; 184 | esac 185 | done 186 | 187 | # If the arguments matched, evaluate the command 188 | # in a subshell. Otherwise, log the failure. 189 | if [ $match_result -eq 0 ] ; then 190 | 191 | # If this is a regular command, push the regular command index for the next stub invocation 192 | if [[ -n $line_flag_regular ]]; then 193 | update_runfile_index 194 | else 195 | STUB_RUNCOUNTS[$no_order_command_index]=$((STUB_RUNCOUNTS[no_order_command_index]+1)) 196 | fi 197 | 198 | # Release the lock while running the payload to allow another `stub' 199 | # of the same program to run concurrently (e.g. in a pipeline). 200 | release_lock 201 | 202 | ( eval "$command" ) && status="$?" || status="$?" 203 | 204 | break 205 | fi 206 | 207 | done < "$STUB_PLAN" 208 | 209 | #If we never matched anything, we failed. 210 | if [[ $match_result -eq 1 ]]; then 211 | STUB_RESULT=1 212 | 213 | #This also means that we never released the lock 214 | # before running the payload 215 | else 216 | acquire_lock 217 | fi 218 | # Write out the match_result information. 219 | update_runfile_result 220 | release_lock 221 | 222 | exit "$status" 223 | 224 | fi 225 | 226 | # Verification mode (`unstub') 227 | if [[ -n $STUB_END ]]; then 228 | 229 | # `unstub' is supposed to run after any stubs are finished 230 | release_lock 231 | 232 | # If the number of regular commands in the plan is larger than 233 | # the final regular_command_index, we failed. 234 | if [[ $(grep -Ee '^-' "$STUB_PLAN" | wc -l ) -ge $STUB_INDEX ]]; then 235 | STUB_RESULT=1 236 | fi 237 | 238 | # If no-order commands weren't executed exactly once 239 | # and multiple-times commands at least once, we failed. 240 | no_order_command_index=0 241 | while IFS= read -r line; do 242 | line_flags="${line%% *}" 243 | line="${line#${line_flags} }" 244 | line_flag_no_order="$(if [[ $line_flags == N ]]; then echo 1; fi)" 245 | line_flag_multiple="$(if [[ $line_flags == M ]]; then echo 1; fi)" 246 | line_flag_regular="$(if [[ $line_flags == - ]]; then echo 1; fi)" 247 | unset line_flags 248 | 249 | if [[ -z $line_flag_regular ]]; then 250 | continue 251 | fi 252 | 253 | no_order_command_index=$((no_order_command_index + 1)) 254 | 255 | if [[ ( -n $line_flag_no_order && \ 256 | (( STUB_RUNCOUNTS[no_order_command_index] != 1 )) ) \ 257 | || \ 258 | ( -n $line_flag_multiple && \ 259 | (( STUB_RUNCOUNTS[no_order_command_index] < 1 )) ) ]] 260 | then 261 | STUB_RESULT=1 262 | fi 263 | 264 | done < "$STUB_PLAN" 265 | 266 | if [[ $STUB_RESULT -ne 0 ]]; then 267 | { 268 | echo "plan:" 269 | cat "$STUB_PLAN" || true 270 | echo "log:" 271 | cat "$STUB_LOG" || true 272 | } >&2 273 | fi 274 | 275 | # Clean up the run file. 276 | rm -f "$STUB_RUN" 277 | rm -f "$STUB_LOG" 278 | 279 | # Return the run result. 280 | exit "$STUB_RESULT" 281 | 282 | fi 283 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pyenv-virtualenv 2 | 3 | [![Join the chat at https://gitter.im/yyuu/pyenv-virtualenv](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/yyuu/pyenv-virtualenv?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 4 | 5 | [![Build Status](https://travis-ci.org/pyenv/pyenv-virtualenv.svg?branch=master)](https://travis-ci.org/pyenv/pyenv-virtualenv) 6 | 7 | pyenv-virtualenv is a [pyenv](https://github.com/pyenv/pyenv) plugin 8 | that provides features to manage virtualenvs and conda environments 9 | for Python on UNIX-like systems. 10 | 11 | (NOTICE: If you are an existing user of [virtualenvwrapper](http://pypi.python.org/pypi/virtualenvwrapper) 12 | and you love it, [pyenv-virtualenvwrapper](https://github.com/pyenv/pyenv-virtualenvwrapper) may help you 13 | (additionally) to manage your virtualenvs.) 14 | 15 | ## Installation 16 | 17 | ### Installing as a pyenv plugin 18 | 19 | This will install the latest development version of pyenv-virtualenv into 20 | the `$(pyenv root)/plugins/pyenv-virtualenv` directory. 21 | 22 | **Important note:** If you installed pyenv into a non-standard directory, make 23 | sure that you clone this repo into the 'plugins' directory of wherever you 24 | installed into. 25 | 26 | From inside that directory you can: 27 | - Check out a specific release tag. 28 | - Get the latest development release by running `git pull` to download the 29 | latest changes. 30 | 31 | 💡 **WSL note:** If you're using WSL, we recommend setting Git to use Unix-style line endings to prevent script execution errors: 32 | 33 | ```sh 34 | git config --global core.autocrlf input 35 | ``` 36 | 37 | 1. **Check out pyenv-virtualenv into plugin directory** 38 | 39 | ```bash 40 | git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv 41 | ``` 42 | 43 | For the Fish shell: 44 | 45 | ```fish 46 | git clone https://github.com/pyenv/pyenv-virtualenv.git (pyenv root)/plugins/pyenv-virtualenv 47 | ``` 48 | 49 | 2. (OPTIONAL) **Add `pyenv virtualenv-init` to your shell** to enable auto-activation of virtualenvs. This is entirely optional but pretty useful. See "Activate virtualenv" below. 50 | 51 | ```bash 52 | echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc 53 | ``` 54 | 55 | **Fish shell note**: Add this to your `~/.config/fish/config.fish` 56 | 57 | ```fish 58 | status --is-interactive; and pyenv virtualenv-init - | source 59 | ``` 60 | 61 | **Zsh note**: Modify your `~/.zshrc` file instead of `~/.bashrc`. 62 | 63 | 3. **Restart your shell to enable pyenv-virtualenv** 64 | 65 | ```bash 66 | exec "$SHELL" 67 | ``` 68 | 69 | 70 | ### Installing with Homebrew (for macOS users) 71 | 72 | macOS users can install pyenv-virtualenv with the 73 | [Homebrew](https://brew.sh) package manager. 74 | This will give you access to the `pyenv-virtualenv` command. If you have pyenv 75 | installed, you will also be able to use the `pyenv virtualenv` command. 76 | 77 | *This is the recommended method of installation if you installed pyenv 78 | with Homebrew.* 79 | 80 | ```sh 81 | brew install pyenv-virtualenv 82 | ``` 83 | 84 | Or, if you would like to install the latest development release: 85 | 86 | ```sh 87 | brew install --HEAD pyenv-virtualenv 88 | ``` 89 | 90 | After installation, you'll still need to do 91 | [Pyenv shell setup steps](https://github.com/pyenv/pyenv#b-set-up-your-shell-environment-for-pyenv) 92 | then add 93 | ```sh 94 | eval "$(pyenv virtualenv-init -)" 95 | ``` 96 | to your shell's `.rc` file (as stated in the caveats). You'll only ever have to do this once. 97 | 98 | 99 | ## Usage 100 | 101 | ### Using `pyenv virtualenv` with pyenv 102 | 103 | To create a virtualenv for the Python version used with pyenv, run 104 | `pyenv virtualenv`, specifying the Python version you want and the name 105 | of the virtualenv directory. For example, 106 | 107 | ```sh 108 | pyenv virtualenv 2.7.10 my-virtual-env-2.7.10 109 | ``` 110 | 111 | will create a virtualenv based on Python 2.7.10 under `$(pyenv root)/versions` in a 112 | folder called `my-virtual-env-2.7.10`. 113 | 114 | `pyenv virtualenv` forwards any options to the underlying command that actually 115 | creates the virtual environment (`conda`, `virtualenv`, or `python -m venv`). 116 | See the output of `pyenv virtualenv --help` for details. 117 | 118 | ### Create virtualenv from current version 119 | 120 | If there is only one argument given to `pyenv virtualenv`, the virtualenv will 121 | be created with the given name based on the current pyenv Python version. 122 | 123 | ```sh 124 | $ pyenv version 125 | 3.4.3 (set by /home/yyuu/.pyenv/version) 126 | $ pyenv virtualenv venv34 127 | ``` 128 | 129 | 130 | ### List existing virtualenvs 131 | 132 | `pyenv virtualenvs` shows you the list of existing virtualenvs and `conda` environments. 133 | 134 | ```sh 135 | $ pyenv shell venv34 136 | $ pyenv virtualenvs 137 | miniconda3-3.9.1 (created from /home/yyuu/.pyenv/versions/miniconda3-3.9.1) 138 | miniconda3-3.9.1/envs/myenv (created from /home/yyuu/.pyenv/versions/miniconda3-3.9.1) 139 | 2.7.10/envs/my-virtual-env-2.7.10 (created from /home/yyuu/.pyenv/versions/2.7.10) 140 | 3.4.3/envs/venv34 (created from /home/yyuu/.pyenv/versions/3.4.3) 141 | my-virtual-env-2.7.10 (created from /home/yyuu/.pyenv/versions/2.7.10) 142 | * venv34 (created from /home/yyuu/.pyenv/versions/3.4.3) 143 | ``` 144 | 145 | There are two entries for each virtualenv, and the shorter one is just a symlink. 146 | 147 | 148 | ### Activate virtualenv 149 | 150 | Some external tools (e.g. [jedi](https://github.com/davidhalter/jedi)) might 151 | require you to `activate` the virtualenv and `conda` environments. 152 | 153 | If `eval "$(pyenv virtualenv-init -)"` is configured in your shell, `pyenv-virtualenv` will automatically activate/deactivate virtualenvs on entering/leaving directories which contain a `.python-version` file that contains the name of a valid virtual environment as shown in the output of `pyenv virtualenvs` (e.g., `venv34` or `3.4.3/envs/venv34` in example above) . `.python-version` files are used by pyenv to denote local Python versions and can be created and deleted with the [`pyenv local`](https://github.com/pyenv/pyenv/blob/master/COMMANDS.md#pyenv-local) command. 154 | 155 | You can also activate and deactivate a pyenv virtualenv manually: 156 | 157 | ```sh 158 | pyenv activate 159 | pyenv deactivate 160 | ``` 161 | 162 | 163 | ### Delete existing virtualenv 164 | 165 | Removing the directories in `$(pyenv root)/versions` and `$(pyenv root)/versions/{version}/envs` will delete the virtualenv, or you can run: 166 | 167 | ```sh 168 | pyenv uninstall my-virtual-env 169 | ``` 170 | 171 | You can also delete existing virtualenvs by using `virtualenv-delete` command, e.g. you can run: 172 | ```sh 173 | pyenv virtualenv-delete my-virtual-env 174 | ``` 175 | This will delete virtualenv called `my-virtual-env`. 176 | 177 | 178 | ### virtualenv and venv 179 | 180 | There is a [venv](http://docs.python.org/3/library/venv.html) module available 181 | for CPython 3.3 and newer. 182 | It provides an executable module `venv` which is the successor of `virtualenv` 183 | and distributed by default. 184 | 185 | `pyenv-virtualenv` uses `python -m venv` if it is available and the `virtualenv` 186 | command is not available. 187 | 188 | 189 | ### Anaconda and Miniconda 190 | 191 | You can manage `conda` environments by `conda create` as same manner as standard Anaconda/Miniconda installations. 192 | To use those environments, you can use `pyenv activate` and `pyenv deactivate`. 193 | 194 | ```sh 195 | $ pyenv version 196 | miniconda3-3.9.1 (set by /home/yyuu/.pyenv/version) 197 | $ conda env list 198 | # conda environments: 199 | # 200 | myenv /home/yyuu/.pyenv/versions/miniconda3-3.9.1/envs/myenv 201 | root * /home/yyuu/.pyenv/versions/miniconda3-3.9.1 202 | $ pyenv activate miniconda3-3.9.1/envs/myenv 203 | discarding /home/yyuu/.pyenv/versions/miniconda3-3.9.1/bin from PATH 204 | prepending /home/yyuu/.pyenv/versions/miniconda3-3.9.1/envs/myenv/bin to PATH 205 | $ python --version 206 | Python 3.4.3 :: Continuum Analytics, Inc. 207 | $ pyenv deactivate 208 | discarding /home/yyuu/.pyenv/versions/miniconda3-3.9.1/envs/myenv/bin from PATH 209 | ``` 210 | 211 | If `conda` is available, `pyenv virtualenv` will use it to create environment by `conda create`. 212 | 213 | ```sh 214 | $ pyenv version 215 | miniconda3-3.9.1 (set by /home/yyuu/.pyenv/version) 216 | $ pyenv virtualenv myenv2 217 | $ conda env list 218 | # conda environments: 219 | # 220 | myenv /home/yyuu/.pyenv/versions/miniconda3-3.9.1/envs/myenv 221 | myenv /home/yyuu/.pyenv/versions/miniconda3-3.9.1/envs/myenv2 222 | root * /home/yyuu/.pyenv/versions/miniconda3-3.9.1 223 | ``` 224 | 225 | You can use version like `miniconda3-3.9.1/envs/myenv` to specify `conda` environment as a version in pyenv. 226 | 227 | ```sh 228 | $ pyenv version 229 | miniconda3-3.9.1 (set by /home/yyuu/.pyenv/version) 230 | $ pyenv shell miniconda3-3.9.1/envs/myenv 231 | $ which python 232 | /home/yyuu/.pyenv/versions/miniconda3-3.9.1/envs/myenv/bin/python 233 | ``` 234 | 235 | 236 | ### Special environment variables 237 | 238 | You can set certain environment variables to control pyenv-virtualenv. 239 | 240 | * `PYENV_VIRTUALENV_CACHE_PATH`, if set, specifies a directory to use for 241 | caching downloaded package files. 242 | * `VIRTUALENV_VERSION`, if set, forces pyenv-virtualenv to install the desired 243 | version of virtualenv. If `virtualenv` has not been installed, 244 | pyenv-virtualenv will try to install the given version of virtualenv. 245 | * `GET_PIP`, if set and `venv` is preferred over `virtualenv`, 246 | use `get_pip.py` from the specified location. 247 | * `GET_PIP_URL`, if set and `venv` is preferred over 248 | `virtualenv`, download `get_pip.py` from the specified URL. 249 | * `PIP_VERSION`, if set and `venv` is preferred 250 | over `virtualenv`, install the specified version of pip. 251 | * `PYENV_VIRTUALENV_VERBOSE_ACTIVATE`, if set, shows some verbose outputs on activation and deactivation 252 | * `PYENV_VIRTUALENV_PROMPT`, if set, allows users to customize how `pyenv-virtualenv` modifies their shell prompt. The default prompt ("(venv)") is overwritten with any user-specified text. Specify the location of the virtual environment name with the string `{venv}`. For example, the default prompt string would be `({venv})`. 253 | 254 | ## Version History 255 | 256 | See [CHANGELOG.md](CHANGELOG.md). 257 | 258 | 259 | ### License 260 | 261 | [(The MIT License)](LICENSE) 262 | 263 | * Copyright (c) 2015 Yamashita, Yuu 264 | 265 | Permission is hereby granted, free of charge, to any person obtaining 266 | a copy of this software and associated documentation files (the 267 | "Software"), to deal in the Software without restriction, including 268 | without limitation the rights to use, copy, modify, merge, publish, 269 | distribute, sublicense, and/or sell copies of the Software, and to 270 | permit persons to whom the Software is furnished to do so, subject to 271 | the following conditions: 272 | 273 | The above copyright notice and this permission notice shall be 274 | included in all copies or substantial portions of the Software. 275 | 276 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 277 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 278 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 279 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 280 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 281 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 282 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 283 | -------------------------------------------------------------------------------- /test/deactivate.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | setup() { 6 | export PYENV_ROOT="${TMP}/pyenv" 7 | unset PYENV_VERSION 8 | unset PYENV_ACTIVATE_SHELL 9 | unset PYENV_VIRTUAL_ENV 10 | unset VIRTUAL_ENV 11 | unset CONDA_DEFAULT_ENV 12 | unset PYTHONHOME 13 | unset _OLD_VIRTUAL_PYTHONHOME 14 | unset PYENV_VIRTUALENV_VERBOSE_ACTIVATE 15 | unset PYENV_VIRTUALENV_DISABLE_PROMPT 16 | unset PYENV_VIRTUAL_ENV_DISABLE_PROMPT 17 | unset VIRTUAL_ENV_DISABLE_PROMPT 18 | unset _OLD_VIRTUAL_PS1 19 | stub pyenv-hooks "deactivate : echo" 20 | } 21 | 22 | @test "deactivate virtualenv" { 23 | export PYENV_VIRTUALENV_INIT=1 24 | export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" 25 | export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" 26 | export PYENV_ACTIVATE_SHELL= 27 | 28 | PYENV_SHELL="bash" run pyenv-sh-deactivate 29 | 30 | assert_success 31 | assert_output </dev/null 2>&1; then 47 | unset -f deactivate; 48 | fi; 49 | EOS 50 | } 51 | 52 | @test "deactivate virtualenv (quiet)" { 53 | export PYENV_VIRTUALENV_INIT=1 54 | export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" 55 | export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" 56 | export PYENV_ACTIVATE_SHELL= 57 | 58 | PYENV_SHELL="bash" run pyenv-sh-deactivate --quiet 59 | 60 | assert_success 61 | assert_output </dev/null 2>&1; then 77 | unset -f deactivate; 78 | fi; 79 | EOS 80 | } 81 | 82 | @test "deactivate virtualenv (verbose)" { 83 | export PYENV_VIRTUALENV_INIT=1 84 | export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" 85 | export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" 86 | export PYENV_ACTIVATE_SHELL= 87 | export PYENV_VIRTUALENV_VERBOSE_ACTIVATE=1 88 | 89 | PYENV_SHELL="bash" run pyenv-sh-deactivate --verbose 90 | 91 | assert_success 92 | assert_output </dev/null 2>&1; then 109 | unset -f deactivate; 110 | fi; 111 | EOS 112 | } 113 | 114 | @test "deactivate virtualenv (with shell activation)" { 115 | export PYENV_VIRTUALENV_INIT=1 116 | export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" 117 | export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" 118 | export PYENV_ACTIVATE_SHELL=1 119 | 120 | PYENV_SHELL="bash" run pyenv-sh-deactivate 121 | 122 | assert_success 123 | assert_output </dev/null 2>&1; then 141 | unset -f deactivate; 142 | fi; 143 | EOS 144 | } 145 | 146 | @test "deactivate virtualenv (with shell activation) (quiet)" { 147 | export PYENV_VIRTUALENV_INIT=1 148 | export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" 149 | export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" 150 | export PYENV_ACTIVATE_SHELL=1 151 | 152 | PYENV_SHELL="bash" run pyenv-sh-deactivate --quiet 153 | 154 | assert_success 155 | assert_output </dev/null 2>&1; then 173 | unset -f deactivate; 174 | fi; 175 | EOS 176 | } 177 | 178 | @test "deactivate virtualenv which has been activated manually" { 179 | export PYENV_VIRTUALENV_INIT=1 180 | export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" 181 | export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" 182 | export PYENV_ACTIVATE_SHELL= 183 | 184 | PYENV_SHELL="bash" run pyenv-sh-deactivate 185 | 186 | assert_success 187 | assert_output </dev/null 2>&1; then 203 | unset -f deactivate; 204 | fi; 205 | EOS 206 | } 207 | 208 | @test "deactivate virtualenv (fish)" { 209 | export PYENV_VIRTUALENV_INIT=1 210 | export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" 211 | export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" 212 | export PYENV_ACTIVATE_SHELL= 213 | 214 | PYENV_SHELL="fish" run pyenv-sh-deactivate 215 | 216 | assert_success 217 | assert_output < X.Y.Z 94 | 95 | #### v20160716 96 | 97 | * Suppress activate/deactivate messages by default (#169, #170, #171) 98 | * Source conda package activate/deactivat scripts if exist (#173) 99 | * Use `source` in favor of `.` for `fish` (#175) 100 | * Use `python -m venv` instead of `pyvenv` due to deprecation of `pyvenv` after 3.6 (#184, #185) 101 | 102 | #### v20160315 103 | 104 | * Evaluate `${PATH}` when outputted code is eval'd. (#154) 105 | * Set proper `CONDA_DEFAULT_ENV` for shorter name (#160) 106 | 107 | #### v20160202 108 | 109 | * Install virtualenv 13.1.2 for CPython/Stackless 3.2.x (yyuu/pyenv#531) 110 | 111 | #### v20160112 112 | 113 | * Fix problem with `virtualenv` to look up executables from source version with `--system-site-packages` (#62) 114 | 115 | #### v20151229 116 | 117 | * Fix `deactivate` error on `fish` (#136) 118 | 119 | #### v20151222 120 | 121 | * Improved interoperability with Anaconda/Miniconda (#103, #106, #107, #108) 122 | * Create `virtualenv` inside `envs` directory of source version, like Anaconda/Miniconda (#103, #107) 123 | * Rewrite `pyenv activate` and `pyenv deactivate` without using scripts provided by virtualenv and conda (#51, #69, #103, #104, #121) 124 | * Improve the `pyenv activate` behaviour on multiple versions (#105, #111) 125 | * Reject creating a virtualenv named `system` (yyuu/pyenv#475) 126 | * Add `--skip-aliases` to `pyenv virtualenvs` (#120) 127 | * Stop showing `version not installed` warning messages in precmd (#49) 128 | 129 | #### v20151103 130 | 131 | * Passing return value from executed command. (#100) 132 | * Add workaround for commands installed in a virtual environment created by `pyvenv` (#62) 133 | * init: zsh: prepend hook to `precmd_functions` (#101) 134 | 135 | #### v20151006 136 | 137 | * Ignore user's site-packages on ensurepip/get-pip (#89) 138 | * Find `python-config` from source version if current version is a virtualenv 139 | * Fix pyenv-virtualenv-init script for fish where command was in string and not being evaluated (#98) 140 | * Add foolproof for `-p` argument. (yyuu/pyenv#98) 141 | 142 | #### v20150719 143 | 144 | * Add support for `conda` environments created by Anaconda/Miniconda (#91) 145 | * Look up commands for original version as well if the environment is created with `--system-site-packages` (#62) 146 | * Add error message if the source version is not installed (#83) 147 | 148 | #### v20150526 149 | 150 | * Use `typeset -g` with `precmd_functions` (#75) 151 | * activate: display setup instructions only with `PYENV_VIRTUALENV_INIT=0` (#78) 152 | * Ignore failure of pyenv activate (#68) 153 | 154 | #### v20150119 155 | 156 | * Ignore errors from `pyenv-version-name` since it might fail if there is configuration error (yyuu/pyenv#291) 157 | * The _shell_ version set in `activate` should be unset in `deactivate` (#61) 158 | * Anaconda has `activate` script nevertheless it is not a virtual environment (#65) 159 | 160 | #### v20141106 161 | 162 | * Stop creating after `ensurepip` since it has done by `ensurepip` itself 163 | * Suppress some useless warnings from `pyenv virtualenv-init` 164 | 165 | #### v20141012 166 | 167 | * Fix warnings from `shellcheck` to improve support for POSIX sh (#40) 168 | * Do not allow whitespace in `VIRTUALENV_NAME` (#44) 169 | * Should not persist `PYENV_DEACTIVATE` after automatic deactivation (#47, #48) 170 | 171 | #### v20140705 172 | 173 | * Display information on auto-(de)?activation 174 | * Support manual (de)?activation with auto-activation enabled (#32, #34) 175 | * Exit as error when (de)?activation failed 176 | * Use https://bootstrap.pypa.io/ to install setuptools and pip 177 | * Create backup of original virtualenv within `$(pyenv root)/versions` when `--upgrade` 178 | 179 | #### v20140615 180 | 181 | * Fix incompatibility issue of `pyenv activate` and `pyenv deactivate` (#26) 182 | * Workaround for the issue with pyenv-which-ext (#26) 183 | 184 | #### v20140614 185 | 186 | * Add `pyenv virtualenv-init` to enable auto-activation feature (#24) 187 | * Create symlinks for executables with version suffix (yyuu/pyenv#182) 188 | 189 | #### v20140602 190 | 191 | * Use new style GH raw url to avoid redirects (raw.github.com -> raw.githubusercontent.com) 192 | * Repaired virtualenv activation and deactivation for the fish shell (#23) 193 | 194 | #### v20140421 195 | 196 | * Display error if `pyenv activate` was invoked as a command 197 | * Fix completion of `pyenv activate` (#15) 198 | * Use `virtualenv` instead of `pyvenv` if `-p` has given (yyuu/pyenv#158) 199 | 200 | #### v20140123 201 | 202 | * Add `activate` and `deactivate` to make `pyenv-virtualenv` work with [jedi](https://github.com/davidhalter/jedi) (#9) 203 | * Use `ensurepip` to install `pip` if it is available 204 | * Unset `PIP_REQUIRE_VENV` to avoid problem on the installation of `virtualenv` (#10) 205 | * Add tests 206 | 207 | #### v20140110.1 208 | 209 | * Fix install script 210 | 211 | #### v20140110 212 | 213 | * Support environment variables of `EZ_SETUP` and `GET_PIP`. 214 | * Support a short option `-p` of `virtualenv`. 215 | 216 | #### v20131216 217 | 218 | * Use latest release of setuptools and pip if the version not given via environment variables. 219 | 220 | #### v20130622 221 | 222 | * Removed bundled `virtualenv.py` script. Now pyenv-virtualenv installs `virtualenv` package into source version and then use it. 223 | * On Python 3.3+, use `pyvenv` as virtualenv command if `virtualenv` is not available. 224 | * Install setuptools and pip into environments created by `pyvenv`. 225 | 226 | #### v20130614 227 | 228 | * Add `pyenv virtualenvs` to list all virtualenv versions. 229 | * *EXPERIMENTAL*: Add `--upgrade` option to re-create virtualenv with migrating packages 230 | 231 | #### v20130527 232 | 233 | * Remove `python-virtualenv` which was no longer used. 234 | * Change the installation path of the `virtualenv.py` script. (`./libexec` -> `./libexec/pyenv-virtualenv/${VIRTUALENV_VERSION}`) 235 | * Download `virtualenv.py` if desired version has not been installed. 236 | 237 | #### v20130507 238 | 239 | * Display virtualenv information in `--help` and `--version` 240 | * Update virtualenv version; 1.8.4 -> 1.9.1 241 | 242 | #### v20130307 243 | 244 | * Rename the project; `s/python-virtualenv/pyenv-virtualenv/g` 245 | * The `pyenv-virtualenv` script is not depending on `python-virtualenv` now. 246 | `python-virtualenv` will left for compatibility and will not continue for future releases. 247 | * Update virtualenv version; 1.8.2 -> 1.8.4 248 | 249 | #### v20130218 250 | 251 | * Add pyenv 0.2.x (rbenv 0.4.x) style help messages. 252 | 253 | #### v20121023 254 | 255 | * Create virtualenv with exact name of python executables. 256 | * Changed command-line options of python-virtualenv. 257 | First argument should be a path to the python executable. 258 | * Add install script. 259 | 260 | #### v20120927 261 | 262 | * Initial public release. 263 | 264 | -------------------------------------------------------------------------------- /test/activate.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | setup() { 6 | export HOME="${TMP}" 7 | export PYENV_ROOT="${TMP}/pyenv" 8 | unset PYENV_VERSION 9 | unset PYENV_ACTIVATE_SHELL 10 | unset VIRTUAL_ENV 11 | unset CONDA_DEFAULT_ENV 12 | unset PYTHONHOME 13 | unset _OLD_VIRTUAL_PYTHONHOME 14 | unset PYENV_VIRTUALENV_VERBOSE_ACTIVATE 15 | unset PYENV_VIRTUALENV_DISABLE_PROMPT 16 | unset PYENV_VIRTUAL_ENV_DISABLE_PROMPT 17 | unset VIRTUAL_ENV_DISABLE_PROMPT 18 | unset PYENV_VIRTUALENV_PROMPT 19 | unset _OLD_VIRTUAL_PS1 20 | stub pyenv-hooks "activate : echo" 21 | } 22 | 23 | @test "activate virtualenv from current version" { 24 | export PYENV_VIRTUALENV_INIT=1 25 | 26 | stub pyenv-version-name "echo venv" 27 | stub pyenv-virtualenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\"" 28 | stub pyenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\"" 29 | stub pyenv-sh-deactivate "--force --quiet : echo deactivated" 30 | 31 | PYENV_SHELL="bash" PYENV_VERSION="venv" run pyenv-sh-activate 32 | 33 | assert_success 34 | assert_output < 6 | # pyenv virtualenv --version 7 | # pyenv virtualenv --help 8 | # 9 | # -f/--force Install even if the version appears to be installed already. Skip 10 | # prompting for confirmation 11 | # 12 | # Notable VIRTUALENV_OPTIONS passed to venv-creating executable, if applicable: 13 | # -u/--upgrade Imply --force 14 | # 15 | 16 | PYENV_VIRTUALENV_VERSION="1.2.6" 17 | 18 | set -e 19 | [ -n "$PYENV_DEBUG" ] && set -x 20 | 21 | if [ -z "${PYENV_ROOT}" ]; then 22 | PYENV_ROOT="$(pyenv-root)" 23 | fi 24 | 25 | # Provide pyenv completions 26 | if [ "$1" = "--complete" ]; then 27 | exec pyenv-versions --bare 28 | fi 29 | 30 | unset PIP_REQUIRE_VENV 31 | unset PIP_REQUIRE_VIRTUALENV 32 | 33 | # Define library functions 34 | parse_options() { 35 | OPTIONS=() 36 | ARGUMENTS=() 37 | local arg option index 38 | 39 | for arg in "$@"; do 40 | if [ "${arg:0:1}" = "-" ]; then 41 | if [ "${arg:1:1}" = "-" ]; then 42 | OPTIONS[${#OPTIONS[*]}]="${arg:2}" 43 | else 44 | index=1 45 | while option="${arg:$index:1}"; do 46 | [ -n "$option" ] || break 47 | OPTIONS[${#OPTIONS[*]}]="$option" 48 | index=$(($index+1)) 49 | done 50 | fi 51 | else 52 | ARGUMENTS[${#ARGUMENTS[*]}]="$arg" 53 | fi 54 | done 55 | } 56 | 57 | colorize() { 58 | if [ -t 1 ]; then printf "\e[%sm%s\e[m" "$1" "$2" 59 | else echo -n "$2" 60 | fi 61 | } 62 | 63 | resolve_link() { 64 | $(type -p greadlink readlink | head -1) "$1" 65 | } 66 | 67 | abs_dirname() { 68 | local cwd="$(pwd)" 69 | local path="$1" 70 | 71 | while [ -n "$path" ]; do 72 | cd "${path%/*}" 73 | local name="${path##*/}" 74 | path="$(resolve_link "$name" || true)" 75 | done 76 | 77 | pwd 78 | cd "$cwd" 79 | } 80 | 81 | http() { 82 | local method="$1" 83 | local url="$2" 84 | local file="$3" 85 | [ -n "$url" ] || return 1 86 | 87 | if type curl &>/dev/null; then 88 | "http_${method}_curl" "$url" "$file" 89 | elif type wget &>/dev/null; then 90 | "http_${method}_wget" "$url" "$file" 91 | else 92 | echo "error: please install \`curl\` or \`wget\` and try again" >&2 93 | exit 1 94 | fi 95 | } 96 | 97 | http_head_curl() { 98 | curl -qsILf "$1" >&4 2>&1 99 | } 100 | 101 | http_get_curl() { 102 | curl -C - -o "${2:--}" -qsSLf "$1" 103 | } 104 | 105 | http_head_wget() { 106 | wget -q --spider "$1" >&4 2>&1 107 | } 108 | 109 | http_get_wget() { 110 | wget -nv -c -O "${2:--}" "$1" 111 | } 112 | 113 | version() { 114 | if [[ -z "${PYENV_VERSION:-}" ]]; then 115 | # `PYENV_VERSION` might not be declared if this was invoked via `--version` 116 | export PYENV_VERSION="$(pyenv-version-name)" 117 | fi 118 | detect_venv 119 | local version 120 | if [ -n "${USE_CONDA}" ]; then 121 | version="$(pyenv-exec conda --version 2>/dev/null || true)" 122 | echo "pyenv-virtualenv ${PYENV_VIRTUALENV_VERSION} (conda ${version:-unknown})" 123 | else 124 | if [ -n "$USE_M_VENV" ]; then 125 | echo "pyenv-virtualenv ${PYENV_VIRTUALENV_VERSION} (${M_VENV_PYTHON_BIN:-python} -m venv)" 126 | else 127 | version="$(pyenv-exec virtualenv --version 2>/dev/null || true)" 128 | echo "pyenv-virtualenv ${PYENV_VIRTUALENV_VERSION} (virtualenv ${version:-unknown})" 129 | fi 130 | fi 131 | } 132 | 133 | usage() { 134 | # We can remove the sed fallback once pyenv 0.2.0 is widely available. 135 | pyenv-help virtualenv 2>/dev/null || sed -ne '/^#/!q;s/.//;s/.//;1,4d;p' < "$0" 136 | if [ -n "${USE_CONDA}" ]; then 137 | pyenv-exec conda create --help 2>/dev/null || true 138 | else 139 | if [ -n "${USE_M_VENV}" ]; then 140 | pyenv-exec "${M_VENV_PYTHON_BIN:-python}" -m venv --help 2>/dev/null || true 141 | else 142 | pyenv-exec virtualenv --help 2>/dev/null || true 143 | fi 144 | fi 145 | [ -z "$1" ] || exit "$1" 146 | } 147 | 148 | detect_venv() { 149 | # Check the existence of executables as a workaround for the issue with pyenv-which-ext 150 | # https://github.com/yyuu/pyenv-virtualenv/issues/26 151 | local prefix="$(pyenv-prefix)" 152 | if [ -x "${prefix}/bin/conda" ]; then 153 | HAS_CONDA=1 154 | else 155 | if [ -x "${prefix}/bin/virtualenv" ]; then 156 | HAS_VIRTUALENV=1 157 | fi 158 | local python 159 | local -a pythons 160 | if [[ $PYENV_VERSION == "system" ]]; then 161 | # Prefer `python3.x` executable if available (#206, #282) 162 | pythons=("python3" "python" "python2") 163 | else 164 | # as per PEP 394, custom activated Python environments should provide the "python" command 165 | # this includes Pyenv-provided installations 166 | pythons=("python") 167 | fi 168 | for python in "${pythons[@]}"; do 169 | if pyenv-exec "${python}" -m venv --help 1>/dev/null 2>&1; then 170 | HAS_M_VENV=1 171 | M_VENV_PYTHON_BIN="${python}" 172 | break 173 | fi 174 | done 175 | fi 176 | # Use `python -m venv` only if there is venv available, virtualenv is not installed, and `-p` not given 177 | if [ -n "${HAS_CONDA}" ]; then 178 | USE_CONDA=1 179 | else 180 | if [ -n "${HAS_M_VENV}" ] && [ -z "${HAS_VIRTUALENV}" ] && [ -z "${VIRTUALENV_PYTHON}" ]; then 181 | USE_M_VENV=1 182 | fi 183 | fi 184 | } 185 | 186 | build_package_ez_setup() { 187 | local ez_setup="${PYENV_VIRTUALENV_CACHE_PATH}/ez_setup.py" 188 | rm -f "${ez_setup}" 189 | { if [ "${EZ_SETUP+defined}" ] && [ -f "${EZ_SETUP}" ]; then 190 | echo "Installing setuptools from ${EZ_SETUP}..." 1>&2 191 | cat "${EZ_SETUP}" 192 | else 193 | [ -n "${EZ_SETUP_URL}" ] 194 | echo "Installing setuptools from ${EZ_SETUP_URL}..." 1>&2 195 | http get "${EZ_SETUP_URL}" 196 | fi 197 | } 1> "${ez_setup}" 198 | pyenv-exec python -s "${ez_setup}" ${EZ_SETUP_OPTS} 1>&2 || { 199 | echo "error: failed to install setuptools via ez_setup.py" >&2 200 | return 1 201 | } 202 | } 203 | 204 | build_package_get_pip() { 205 | local get_pip="${PYENV_VIRTUALENV_CACHE_PATH}/get-pip.py" 206 | rm -f "${get_pip}" 207 | { if [ "${GET_PIP+defined}" ] && [ -f "${GET_PIP}" ]; then 208 | echo "Installing pip from ${GET_PIP}..." 1>&2 209 | cat "${GET_PIP}" 210 | else 211 | [ -n "${GET_PIP_URL}" ] 212 | echo "Installing pip from ${GET_PIP_URL}..." 1>&2 213 | http get "${GET_PIP_URL}" 214 | fi 215 | } 1> "${get_pip}" 216 | pyenv-exec python -s "${get_pip}" ${GET_PIP_OPTS} 1>&2 || { 217 | echo "error: failed to install pip via get-pip.py" >&2 218 | return 1 219 | } 220 | } 221 | 222 | build_package_ensurepip() { 223 | pyenv-exec python -s -m ensurepip 2>/dev/null || build_package_get_pip "$@" || return 1 224 | } 225 | 226 | prepare_requirements() { 227 | pyenv-exec pip freeze > "${REQUIREMENTS}" 228 | mv -f "${VIRTUALENV_PATH}" "${VIRTUALENV_ORIG}" 229 | } 230 | 231 | install_requirements() { 232 | if [ -f "${REQUIREMENTS}" ]; then 233 | ## Migrate previously installed packages from requirements.txt 234 | pyenv-exec pip install $QUIET $VERBOSE --requirement "${REQUIREMENTS}" || { 235 | echo 236 | echo "PIP INSTALL FAILED" 237 | echo 238 | echo "Inspect or clean up the original tree at ${VIRTUALENV_ORIG}" 239 | echo 240 | echo "Package list:" 241 | cat "${REQUIREMENTS}" | sed 's/^/ * /' 242 | return 1 243 | } 1>&2 244 | rm -f "${REQUIREMENTS}" 245 | rm -fr "${VIRTUALENV_ORIG}" 246 | fi 247 | } 248 | 249 | PYENV_VIRTUALENV_ROOT="$(abs_dirname "$0")/.." 250 | if [ -z "${PYENV_VIRTUALENV_CACHE_PATH}" ]; then 251 | PYENV_VIRTUALENV_CACHE_PATH="${PYTHON_BUILD_CACHE_PATH:-${PYENV_ROOT}/cache}" 252 | fi 253 | VIRTUALENV_OPTIONS=() 254 | 255 | unset FORCE 256 | unset NO_ENSUREPIP 257 | unset QUIET 258 | unset UPGRADE 259 | unset VERBOSE 260 | unset VIRTUALENV_PYTHON 261 | 262 | parse_options "$@" 263 | for option in "${OPTIONS[@]}"; do 264 | case "$option" in 265 | "f" | "force" ) 266 | FORCE=true 267 | ;; 268 | "h" | "help" ) 269 | usage 0 270 | ;; 271 | "no-pip" ) 272 | NO_ENSUREPIP=1 273 | VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="--$option" 274 | ;; 275 | "no-setuptools" ) 276 | NO_ENSUREPIP=1 277 | VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="--$option" 278 | ;; 279 | "p" | "python" ) 280 | VIRTUALENV_PYTHON="${ARGUMENTS[0]}" 281 | ARGUMENTS=("${ARGUMENTS[@]:1}") # shift 1 282 | ;; 283 | "q" | "quiet" ) 284 | QUIET="--quiet" 285 | ;; 286 | "u" | "upgrade" ) 287 | UPGRADE=true 288 | ;; 289 | "v" | "verbose" ) 290 | VERBOSE="--verbose" 291 | ;; 292 | "version" ) 293 | version 294 | exit 0 295 | ;; 296 | "without-pip" ) 297 | NO_ENSUREPIP=1 298 | VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="--$option" 299 | ;; 300 | * ) # virtualenv long options 301 | if [[ "$option" == "python="* ]]; then 302 | VIRTUALENV_PYTHON="${option#python=}" 303 | else 304 | VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="--$option" 305 | fi 306 | ;; 307 | esac 308 | done 309 | 310 | if [[ "${#ARGUMENTS[@]}" == 0 ]]; then 311 | echo "pyenv-virtualenv: no virtualenv name given." 1>&2 312 | exit 1 313 | elif [[ "${#ARGUMENTS[@]}" == 1 ]]; then 314 | # If only one argument given, use current version as source version 315 | OLDIFS="${IFS}" 316 | IFS=: 317 | VERSION_NAMES=($(pyenv-version-name)) 318 | IFS="${OLDIFS}" 319 | VERSION_NAME="${VERSION_NAMES}" 320 | VIRTUALENV_NAME="${ARGUMENTS[0]}" 321 | else 322 | # Otherwise, use former as source version, and latter as virtualenv version 323 | VERSION_NAME="${ARGUMENTS[0]}" 324 | VIRTUALENV_NAME="${ARGUMENTS[1]}" 325 | fi 326 | 327 | if [[ -n "${VERSION_NAME}" ]] && command -v pyenv-latest >/dev/null; then 328 | VERSION_NAME="$(pyenv-latest -f "${VERSION_NAME}")" 329 | fi 330 | 331 | if [ -z "${VERSION_NAME}" ] || [ -z "${VIRTUALENV_NAME}" ]; then 332 | usage 1 333 | fi 334 | 335 | if [[ "${VIRTUALENV_NAME##*/}" == "system" ]]; then 336 | echo "pyenv-virtualenv: \`system' is not allowed as virtualenv name." 1>&2 337 | exit 1 338 | fi 339 | 340 | if [ "$VIRTUALENV_NAME" != "${VIRTUALENV_NAME%[[:space:]]*}" ]; then 341 | echo "pyenv-virtualenv: no whitespace allowed in virtualenv name." 1>&2 342 | exit 1 343 | fi 344 | 345 | if [ "${VIRTUALENV_NAME}" != "${VIRTUALENV_NAME%/*}" ] && [[ "${VIRTUALENV_NAME}" != "${VERSION_NAME%%/*}/envs/${VIRTUALENV_NAME##*/}" ]] ; then 346 | echo "pyenv-virtualenv: no slash allowed in virtualenv name." 1>&2 347 | exit 1 348 | fi 349 | 350 | # Set VERSION_NAME as default version in this script 351 | export PYENV_VERSION="${VERSION_NAME}" 352 | 353 | not_installed_message() { 354 | local is_available=$(python-build --definitions | grep -F -x "$1") 355 | echo "pyenv-virtualenv: \`${1}' is not installed in pyenv." 1>&2 356 | if [[ $is_available ]]; then 357 | echo "Run \`pyenv install ${1}' to install it." 1>&2 358 | else 359 | echo "It does not look like a valid Python version. See \`pyenv install --list' for available versions." 1>&2 360 | fi 361 | } 362 | 363 | # Source version must exist before creating virtualenv. 364 | PREFIX="$(pyenv-prefix 2>/dev/null || true)" 365 | if [ ! -d "${PREFIX}" ]; then 366 | not_installed_message "${PYENV_VERSION}" 367 | exit 1 368 | fi 369 | 370 | if [ -z "$TMPDIR" ]; then 371 | TMP="/tmp" 372 | else 373 | TMP="${TMPDIR%/}" 374 | fi 375 | 376 | # Not create `system/envs` directory even if source version is `system` 377 | if [[ "${VERSION_NAME%/envs/*}" == "system" ]]; then 378 | VIRTUALENV_NAME="${VIRTUALENV_NAME##*/}" 379 | else 380 | VIRTUALENV_PREFIX="$(pyenv-virtualenv-prefix 2>/dev/null || true)" 381 | if [[ "${VIRTUALENV_PREFIX%/*}" == "${PYENV_ROOT}/versions" ]]; then 382 | VIRTUALENV_NAME="${VIRTUALENV_PREFIX#${PYENV_ROOT}/versions/}/envs/${VIRTUALENV_NAME##*/}" 383 | else 384 | VIRTUALENV_NAME="${VERSION_NAME}/envs/${VIRTUALENV_NAME##*/}" 385 | fi 386 | fi 387 | 388 | VIRTUALENV_PATH="${PYENV_ROOT}/versions/${VIRTUALENV_NAME}" 389 | if [[ "${VIRTUALENV_PATH/*/envs/*}" != "${PYENV_ROOT}/versions" ]]; then 390 | COMPAT_VIRTUALENV_PATH="${PYENV_ROOT}/versions/${VIRTUALENV_NAME##*/}" 391 | fi 392 | 393 | if [ -n "${COMPAT_VIRTUALENV_PATH}" ]; then 394 | if [ -z ${FORCE} ]; then 395 | if [ -e "${COMPAT_VIRTUALENV_PATH}" ] || [ -L "${COMPAT_VIRTUALENV_PATH}" ]; then 396 | echo "pyenv-virtualenv: \`${COMPAT_VIRTUALENV_PATH}' already exists." 1>&2 397 | exit 1 398 | fi 399 | fi 400 | fi 401 | 402 | unset HAS_VIRTUALENV 403 | unset HAS_M_VENV 404 | unset USE_CONDA 405 | unset USE_M_VENV 406 | detect_venv 407 | 408 | SEED="$(date "+%Y%m%d%H%M%S").$$" 409 | VIRTUALENV_ORIG="${VIRTUALENV_PATH}.${SEED}" 410 | REQUIREMENTS="${TMP}/requirements.${SEED}.txt" 411 | 412 | # Upgrade existing virtualenv 413 | if [ -n "$UPGRADE" ]; then 414 | FORCE=1 415 | # `python -m venv` has `--upgrade` by default 416 | if [ -n "${USE_M_VENV}" ]; then 417 | unset UPGRADE 418 | VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="--upgrade" 419 | fi 420 | fi 421 | 422 | if [ -z "${VIRTUALENV_VERSION}" ]; then 423 | case "${PYENV_VERSION}" in 424 | "3.0"* ) 425 | NO_ENSUREPIP=1 426 | ;; 427 | "3.1"* ) 428 | NO_ENSUREPIP=1 429 | ;; 430 | "3.2"* | "stackless-3.2"* ) 431 | # pip 8.x (bundled with virtualenv 14+) doesn't support 3.2 anymore 432 | # https://github.com/yyuu/pyenv/issues/531 433 | VIRTUALENV_VERSION="13.1.2" 434 | NO_ENSUREPIP=1 435 | ;; 436 | esac 437 | fi 438 | 439 | if [ -n "${USE_CONDA}" ]; then 440 | # e.g. `conda create -n py35 python=3.5 anaconda` 441 | if [ -n "${VIRTUALENV_PYTHON}" ]; then 442 | VIRTUALENV_PYTHON="${VIRTUALENV_PYTHON##*/}" 443 | VIRTUALENV_PYTHON="${VIRTUALENV_PYTHON#python}" 444 | if [ -n "${VIRTUALENV_PYTHON}" ]; then 445 | VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="python=${VIRTUALENV_PYTHON}" 446 | fi 447 | fi 448 | else 449 | if [ -n "${USE_M_VENV}" ]; then 450 | # Unset some arguments not supported by `python -m venv` 451 | unset QUIET 452 | unset VERBOSE 453 | if [ -n "${VIRTUALENV_PYTHON}" ]; then 454 | echo "pyenv-virtualenv: \`--python=${VIRTUALENV_PYTHON}' is not supported by \`python -m venv'." 1>&2 455 | exit 1 456 | fi 457 | else 458 | if [ -n "${VIRTUALENV_PYTHON}" ]; then 459 | if [[ "${VIRTUALENV_PYTHON}" == "${VIRTUALENV_PYTHON##*/}" ]] || [[ "${VIRTUALENV_PYTHON}" == "${PYENV_ROOT}/shims/"* ]]; then 460 | python="$(pyenv-which "${VIRTUALENV_PYTHON##*/}" 2>/dev/null || true)" 461 | if [ -x "${python}" ]; then 462 | VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="--python=${python}" 463 | else 464 | python="$(PYENV_VERSION="$(pyenv-whence "${VIRTUALENV_PYTHON##*/}" 2>/dev/null | tail -n 1 || true)" pyenv-which "${VIRTUALENV_PYTHON##*/}" 2>/dev/null || true)" 465 | if [ -x "${python}" ]; then 466 | VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="--python=${python}" 467 | else 468 | # echo "pyenv-virtualenv: \`${VIRTUALENV_PYTHON##*/}' is not installed in pyenv." 1>&2 469 | not_installed_message "${VIRTUALENV_PYTHON##*/}" 470 | exit 1 471 | fi 472 | fi 473 | else 474 | VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="--python=${VIRTUALENV_PYTHON}" 475 | fi 476 | fi 477 | if [ -z "${HAS_VIRTUALENV}" ]; then 478 | if [ -n "${VIRTUALENV_VERSION}" ]; then 479 | virtualenv_spec="virtualenv==${VIRTUALENV_VERSION}" 480 | else 481 | virtualenv_spec="virtualenv" 482 | fi 483 | pyenv-exec pip install $QUIET $VERBOSE "${virtualenv_spec}" 484 | HAS_VIRTUALENV=1 485 | fi 486 | fi 487 | fi 488 | 489 | # Unset environment variables which start with `VIRTUALENV_`. 490 | # These variables are reserved for virtualenv. 491 | unset VIRTUALENV_VERSION 492 | 493 | 494 | # Download specified version of ez_setup.py/get-pip.py. 495 | if [ -z "${EZ_SETUP_URL}" ]; then 496 | if [ -n "${SETUPTOOLS_VERSION}" ]; then 497 | EZ_SETUP_URL="https://bitbucket.org/pypa/setuptools/raw/${SETUPTOOLS_VERSION}/ez_setup.py" 498 | unset SETUPTOOLS_VERSION 499 | else 500 | EZ_SETUP_URL="https://bootstrap.pypa.io/ez_setup.py" 501 | fi 502 | fi 503 | if [ -z "${GET_PIP_URL}" ]; then 504 | if [ -n "${PIP_VERSION}" ]; then 505 | { colorize 1 "WARNING" 506 | echo ": Setting PIP_VERSION=${PIP_VERSION} is no longer supported and may cause failures during the install process." 507 | } 1>&2 508 | GET_PIP_URL="https://raw.githubusercontent.com/pypa/pip/${PIP_VERSION}/contrib/get-pip.py" 509 | # Unset `PIP_VERSION` from environment before invoking `get-pip.py` to deal with "ValueError: invalid truth value" (pypa/pip#4528) 510 | unset PIP_VERSION 511 | else 512 | # Use custom get-pip URL based on the target version (#1127) 513 | case "${PYENV_VERSION}" in 514 | 2.6 | 2.6.* ) 515 | GET_PIP_URL="https://bootstrap.pypa.io/pip/2.6/get-pip.py" 516 | ;; 517 | 2.7 | 2.7.* ) 518 | GET_PIP_URL="https://bootstrap.pypa.io/pip/2.7/get-pip.py" 519 | ;; 520 | 3.2 | 3.2.* ) 521 | GET_PIP_URL="https://bootstrap.pypa.io/pip/3.2/get-pip.py" 522 | ;; 523 | 3.3 | 3.3.* ) 524 | GET_PIP_URL="https://bootstrap.pypa.io/pip/3.3/get-pip.py" 525 | ;; 526 | 3.4 | 3.4.* ) 527 | GET_PIP_URL="https://bootstrap.pypa.io/pip/3.4/get-pip.py" 528 | ;; 529 | 3.5 | 3.5.* ) 530 | GET_PIP_URL="https://bootstrap.pypa.io/pip/3.5/get-pip.py" 531 | ;; 532 | 3.6 | 3.6.* ) 533 | GET_PIP_URL="https://bootstrap.pypa.io/pip/3.6/get-pip.py" 534 | ;; 535 | * ) 536 | GET_PIP_URL="https://bootstrap.pypa.io/pip/get-pip.py" 537 | ;; 538 | esac 539 | fi 540 | fi 541 | 542 | 543 | # Define `before_virtualenv` and `after_virtualenv` functions that allow 544 | # plugin hooks to register a string of code for execution before or 545 | # after the installation process. 546 | declare -a before_hooks after_hooks 547 | 548 | before_virtualenv() { 549 | local hook="$1" 550 | before_hooks["${#before_hooks[@]}"]="$hook" 551 | } 552 | 553 | after_virtualenv() { 554 | local hook="$1" 555 | after_hooks["${#after_hooks[@]}"]="$hook" 556 | } 557 | 558 | # Load plugin hooks. 559 | OLDIFS="$IFS" 560 | IFS=$'\n' scripts=(`pyenv-hooks virtualenv`) 561 | IFS="$OLDIFS" 562 | for script in "${scripts[@]}"; do source "$script"; done 563 | 564 | 565 | [ -d "${VIRTUALENV_PATH}" ] && PREFIX_EXISTS=1 566 | 567 | # If the virtualenv exists, prompt for confirmation unless 568 | # the --force option was specified. 569 | if [ -d "${VIRTUALENV_PATH}/bin" ]; then 570 | if [ -z "$FORCE" ]; then 571 | echo "pyenv-virtualenv: ${VIRTUALENV_PATH} already exists" 1>&2 572 | read -p "continue with installation? (y/N) " 573 | 574 | case "$REPLY" in 575 | y* | Y* ) ;; 576 | * ) exit 1 ;; 577 | esac 578 | fi 579 | 580 | if [ -n "$UPGRADE" ]; then 581 | if [ -n "${NO_ENSUREPIP}" ]; then 582 | echo "pyenv-virtualenv: upgrading will not work with --no-setuptools or --no-pip" 1>&2 583 | exit 1 584 | else 585 | PYENV_VERSION="${VIRTUALENV_NAME}" prepare_requirements 586 | fi 587 | fi 588 | fi 589 | 590 | # Execute `before_virtualenv` hooks. 591 | for hook in "${before_hooks[@]}"; do eval "$hook"; done 592 | 593 | # Plan cleanup on unsuccessful installation. 594 | cleanup() { 595 | [[ -L "${COMPAT_VIRTUALENV_PATH}" ]] && rm "${COMPAT_VIRTUALENV_PATH}" 596 | [ -z "${PREFIX_EXISTS}" ] && rm -rf "$VIRTUALENV_PATH" 597 | } 598 | 599 | trap cleanup SIGINT ERR 600 | 601 | # Invoke virtualenv and record exit status in $STATUS. 602 | STATUS=0 603 | # virtualenv may download distribute/setuptools into the current directory. 604 | # Change to cache directory to reuse them between invocations. 605 | mkdir -p "${PYENV_VIRTUALENV_CACHE_PATH}" 606 | cd "${PYENV_VIRTUALENV_CACHE_PATH}" 607 | if [ -n "${USE_CONDA}" ]; then 608 | if [ -z "$VIRTUALENV_PYTHON" ]; then 609 | #process substitution doesn't seem to work unless it's directly inserted to the command line 610 | #if we add it to VIRTUALENV_OPTIONS instead, "broken pipe" happens 611 | pyenv-exec conda create $QUIET $VERBOSE --name "${VIRTUALENV_PATH##*/}" --yes "${VIRTUALENV_OPTIONS[@]}" --file <(pyenv-exec conda list python --full-name --export) || STATUS="$?" 612 | else 613 | pyenv-exec conda create $QUIET $VERBOSE --name "${VIRTUALENV_PATH##*/}" --yes "${VIRTUALENV_OPTIONS[@]}" || STATUS="$?" 614 | fi 615 | else 616 | if [ -n "${USE_M_VENV}" ]; then 617 | pyenv-exec "${M_VENV_PYTHON_BIN:-python}" -m venv $QUIET $VERBOSE "${VIRTUALENV_OPTIONS[@]}" "${VIRTUALENV_PATH}" || STATUS="$?" 618 | else 619 | pyenv-exec virtualenv $QUIET $VERBOSE "${VIRTUALENV_OPTIONS[@]}" "${VIRTUALENV_PATH}" || STATUS="$?" 620 | fi 621 | fi 622 | 623 | ( 624 | shopt -s nullglob 625 | for extra_binary in "$PREFIX"/bin/python*-config; do 626 | extra_binary_linkname="$VIRTUALENV_PATH/bin/$(basename $extra_binary)" 627 | [[ -e "$extra_binary_linkname" ]] || \ 628 | ln -s "$extra_binary" "$extra_binary_linkname" 629 | done 630 | ) 631 | 632 | ## Create symlink in the `versions` directory for backward compatibility 633 | if [ -d "${VIRTUALENV_PATH}" ] && [ -n "${COMPAT_VIRTUALENV_PATH}" ]; then 634 | # Overwrite an existing link, can happen if running with -f 635 | ln -fsn "${VIRTUALENV_PATH}" "${COMPAT_VIRTUALENV_PATH}" 636 | fi 637 | 638 | if [ ! -e "${VIRTUALENV_PATH}/bin/pydoc" ]; then 639 | mkdir -p "${VIRTUALENV_PATH}/bin" 640 | cat < "${VIRTUALENV_PATH}/bin/pydoc" 641 | #!${VIRTUALENV_PATH}/bin/python 642 | import pydoc 643 | if __name__ == '__main__': 644 | pydoc.cli() 645 | EOS 646 | chmod +x "${VIRTUALENV_PATH}/bin/pydoc" 647 | fi 648 | 649 | if [ -z "${NO_ENSUREPIP}" ]; then 650 | ## Install setuptools and pip. 651 | PYENV_VERSION="${VIRTUALENV_NAME}" build_package_ensurepip 652 | 653 | ## Migrate previously installed packages from requirements.txt. 654 | PYENV_VERSION="${VIRTUALENV_NAME}" install_requirements || true 655 | fi 656 | 657 | # Execute `after_virtualenv` hooks. 658 | for hook in "${after_hooks[@]}"; do eval "$hook"; done 659 | 660 | # Run `pyenv-rehash` after a successful installation. 661 | if [ "$STATUS" == "0" ]; then 662 | pyenv-rehash 663 | else 664 | cleanup 665 | fi 666 | 667 | exit "$STATUS" 668 | --------------------------------------------------------------------------------