Repository: pyenv/pyenv-virtualenv Branch: master Commit: 38f3333f3a24 Files: 49 Total size: 169.7 KB Directory structure: gitextract_nqzhc3gf/ ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ └── feature_request.md │ ├── no-response.yml │ └── workflows/ │ └── tests.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── MAINTENANCE.md ├── README.md ├── bin/ │ ├── pyenv-activate │ ├── pyenv-deactivate │ ├── pyenv-sh-activate │ ├── pyenv-sh-deactivate │ ├── pyenv-virtualenv │ ├── pyenv-virtualenv-delete │ ├── pyenv-virtualenv-init │ ├── pyenv-virtualenv-prefix │ └── pyenv-virtualenvs ├── etc/ │ └── pyenv.d/ │ ├── rehash/ │ │ └── envs.bash │ ├── uninstall/ │ │ └── envs.bash │ └── which/ │ ├── conda.bash │ ├── python-config.bash │ └── system-site-packages.bash ├── install.sh ├── libexec/ │ └── pyenv-virtualenv-realpath ├── shims/ │ ├── activate │ └── deactivate └── test/ ├── activate.bats ├── conda-activate.bats ├── conda-deactivate.bats ├── conda-prefix.bats ├── conda.bats ├── deactivate.bats ├── delete.bats ├── envs.bats ├── hooks.bats ├── init.bats ├── installer.bats ├── pip.bats ├── prefix.bats ├── python.bats ├── pyvenv.bats ├── stubs/ │ └── stub ├── test_helper.bash ├── version.bats ├── virtualenv.bats └── virtualenvs.bats ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: [pyenv] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] patreon: # Replace with a single Patreon username open_collective: pyenv # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve title: '' labels: '' assignees: '' --- ### Prerequisite * [ ] 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. * [ ] Make sure you are reporting a problem in Pyenv-Virtualenv and not seeking consultation with Pyenv-Virtualenv use. * 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). * [ ] Make sure your problem is not derived from packaging (e.g. [Homebrew](https://brew.sh)). * Please refer to the package documentation for the installation issues, etc. * [ ] Make sure your problem is not derived from other plugins. * This repository is maintaining the `pyenv-virtualenv` plugin only. Please refrain from reporting issues of other plugins here. ### Describe the bug A clear and concise description of what the bug is. Do specify what the expected behaviour is if that's not obvious from the bug's nature. #### Reproduction steps Listing the commands to run in a new console session and their output is usually sufficient. Please use a Markdown code block (three backticks on a line by themselves before and after the text) to denote a console output excerpt. #### Diagnostic details - [ ] Platform information (e.g. Ubuntu Linux 20.04): - [ ] OS architecture (e.g. amd64): - [ ] pyenv version: - [ ] pyenv-virtualenv version: - [ ] Python version: - [ ] virtualenv version (if installed): - [ ] Please attach the debug log of a faulty Pyenv invocation as a gist * 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` * If the problem happens outside of a Pyenv invocation, get the debug log like this: ```bash # for Bash export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' # for Zsh export PS4='+(%x:%I): %N(%i): ' set -x set +x ``` ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project title: '' labels: '' assignees: '' --- **Describe the intended use case** * 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) * What you are trying to achieve * What specifically you are doing for that regarding Pyenv * Where you are stuck **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. [ ] 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. **Additional context** Add any other context or screenshots about the feature request here. ================================================ FILE: .github/no-response.yml ================================================ # Configuration for probot-no-response - https://github.com/probot/no-response # Number of days of inactivity before an Issue is closed for lack of response daysUntilClose: 30 # Label requiring a response responseRequiredLabel: need-feedback # Comment to post when closing an Issue for lack of response. Set to `false` to disable closeComment: > This issue has been automatically closed because there has been no response to our request for more information from the original author. With only the information that is currently in the issue, we don't have enough information to take action. Please reach out if you have or find the answers we need so that we can investigate further. ================================================ FILE: .github/workflows/tests.yml ================================================ name: tests on: [pull_request, push] jobs: tests: strategy: fail-fast: false matrix: os: - ubuntu-24.04 - ubuntu-22.04 - macos-15-intel - macos-15 - macos-14 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 - run: git clone https://github.com/bats-core/bats-core.git --depth=1 -b v1.10.0 bats - run: bats/bin/bats --tap test ================================================ FILE: .gitignore ================================================ /bats/ /libexec/pyenv-virtualenv/*/*.class /libexec/pyenv-virtualenv/*/*.pyc /libexec/pyenv-virtualenv/*/*.pyo /libexec/pyenv-virtualenv/*/__pycache__ *.swo *.swp ================================================ FILE: .travis.yml ================================================ sudo: false install: git clone --depth=1 https://github.com/sstephenson/bats.git script: bats/bin/bats --tap test language: c notifications: email: on_success: never deploy: provider: releases api_key: secure: DsGAt0UmTSGVfsNJ6LmM+LvsV6FYmvX4FcET82XrskPiQW+N8+8JZR8WuZxfmwdJZu+dkkdoq6gYgL2xF7m4LxRG7aw3B5TtbMTrJQeW0hdtCSBwbbYyvwcp2m7ywE8lGAfZQITaGj1R6f2Cgh8cgtcrErjcF0KJsYlVlgNv+/M= on: repo: pyenv/pyenv-virtualenv tags: true ================================================ FILE: CHANGELOG.md ================================================ ## Version History #### v1.2.6 * Fix changelog and version numbers #### v1.2.5 * Add prompt customization by @jimenezj8 in https://github.com/pyenv/pyenv-virtualenv/pull/476 * README: fix and distinguish syntax highlighting in Bash vs Fish snippets by @diericx in https://github.com/pyenv/pyenv-virtualenv/pull/489 * Fix pyenv-virtualenv using a different Python version in a conda environment by @native-api in https://github.com/pyenv/pyenv-virtualenv/pull/492 * Fix confusing activate/deactivate error messages when Pyenv is not installed as a shell function by @native-api in https://github.com/pyenv/pyenv-virtualenv/pull/495 * Fix errorneously creating a symlink inside env directory if running w… by @native-api in https://github.com/pyenv/pyenv-virtualenv/pull/496 * Update LICENSE, fix copyright license year by @JasonnnW3000 in https://github.com/pyenv/pyenv-virtualenv/pull/499 * docs: add WSL note about core.autocrlf to prevent CRLF issues by @stoneHee99 in https://github.com/pyenv/pyenv-virtualenv/pull/512 * docs: fix the link to Pyenv shell setup steps by @cshen-dev in https://github.com/pyenv/pyenv-virtualenv/pull/516 * Convert issue template to new Github format by @native-api in https://github.com/pyenv/pyenv-virtualenv/pull/519 * Prevent loss of data on `virtualenv-delete -f` if the env doesn't exist and the PREFIX envvar is set elsewhere by @SabriRamadanTNG in https://github.com/pyenv/pyenv-virtualenv/pull/518 #### v1.2.4 * Fix failing to detect `-m venv` when "python" is not provided by the distro by @native-api in https://github.com/pyenv/pyenv-virtualenv/pull/479 * README: Remove dollar signs from commands that are meant to be copied by @galonsky in https://github.com/pyenv/pyenv-virtualenv/pull/481 * Reflect pyenv-latest switch change in 2.4.8 by @native-api in https://github.com/pyenv/pyenv-virtualenv/pull/484 #### v1.2.3 * Fix: add `colorize` helper by @silverjam in https://github.com/pyenv/pyenv-virtualenv/pull/470 * Bump pyenv-virtualenv reporting version to match release by @ushuz in https://github.com/pyenv/pyenv-virtualenv/pull/471 * Add fish prompt changing by @romirk in https://github.com/pyenv/pyenv-virtualenv/pull/475 * Don't activate if a 3rd-party venv is activated over ours by @native-api in https://github.com/pyenv/pyenv-virtualenv/pull/478 #### v1.2.2 * Prompt removal was never done and is not planned anymore by @native-api in https://github.com/pyenv/pyenv-virtualenv/pull/447 * Update PYENV_VIRTUALENV_VERSION by @jack-mcivor in https://github.com/pyenv/pyenv-virtualenv/pull/449 * Add activate/deactivate hooks by @joshfrench in https://github.com/pyenv/pyenv-virtualenv/pull/452 * More helpful error message when requesting a nonexistent base version by @MarcinKonowalczyk in https://github.com/pyenv/pyenv-virtualenv/pull/454 * Add fish install oneliner by @ElijahLynn in https://github.com/pyenv/pyenv-virtualenv/pull/322 * Link python*-config into VE by @native-api in https://github.com/pyenv/pyenv-virtualenv/pull/460 #### v1.2.1 * Support prefixes resolved by pyenv-latest as base version names by @native-api in https://github.com/pyenv/pyenv-virtualenv/pull/446 #### v1.2.0 * ~/.*rc should be modified instead of ~/.*profile by @native-api in https://github.com/pyenv/pyenv-virtualenv/pull/384 * Fixes #394 - update pyenv virtualenvs to list virtualenvs start with dot prefixes by @Gauravtalreja1 in https://github.com/pyenv/pyenv-virtualenv/pull/395 * Fix installation steps to allow for Pyenv 2 by @native-api in https://github.com/pyenv/pyenv-virtualenv/pull/388 * Fix get-pip.py URLs for older versions of Python by @jivanf in https://github.com/pyenv/pyenv-virtualenv/pull/403 * Add (y/N) prompt help text by @sh-cho in https://github.com/pyenv/pyenv-virtualenv/pull/404 * perf(sh-activate): avoid a pyenv-version-name call by @scop in https://github.com/pyenv/pyenv-virtualenv/pull/380 * Fix unbound variable errors when running `pyenv activate` with `set -u` Use default empty value. This fixes #422. by @ackalker in https://github.com/pyenv/pyenv-virtualenv/pull/423 * Fix another unbound variable error by @ackalker in https://github.com/pyenv/pyenv-virtualenv/pull/424 * Update `get-pip.py` URLs in `pyenv-virtualenv` by @mcdonnnj in https://github.com/pyenv/pyenv-virtualenv/pull/426 * Deduplicate shims in $PATH for the fish shell during initialization by @ericvw in https://github.com/pyenv/pyenv-virtualenv/pull/430 * Upgrade uninstall hook after pyenv/pyenv#2432 by @laggardkernel in https://github.com/pyenv/pyenv-virtualenv/pull/438 * Stop delete force failing when virtualenv does not exist by @eganjs in https://github.com/pyenv/pyenv-virtualenv/pull/330 * fix: relative path to pyenv-realpath.dylib by @scop in https://github.com/pyenv/pyenv-virtualenv/pull/378 * Spelling fixes by @scop in https://github.com/pyenv/pyenv-virtualenv/pull/352 * Clone bats with --depth=1, gitignore it by @scop in https://github.com/pyenv/pyenv-virtualenv/pull/351 * set -u fixes by @scop in https://github.com/pyenv/pyenv-virtualenv/pull/350 * Set up Github Actions CI by @native-api in https://github.com/pyenv/pyenv-virtualenv/pull/440 * Enhance documentation about options for `pyenv virtualenv` by @pylipp in https://github.com/pyenv/pyenv-virtualenv/pull/425 * Return control to pyenv-uninstall in uninstall/envs.bash by @aiguofer in https://github.com/pyenv/pyenv-virtualenv/pull/321 * Use realpath of scripts to determine relative locations by @andrew-christianson in https://github.com/pyenv/pyenv-virtualenv/pull/308 * Shell detect improvements by @scop in https://github.com/pyenv/pyenv-virtualenv/pull/377 #### v1.1.5 * Fix install script (#290, #302) #### v1.1.4 * Support newer conda (#290) * Prefer `python3.x` executable if available (#206, #282, #296) #### v1.1.3 * No code changes since 1.1.2 #### v1.1.2 * Use custom get-pip URL based on the target version (#253, #254, #255) * Source conda 4.4.4 shell files (#251) * Evaluate force flag before testing if venv exists (#232) #### v1.1.1 * Set `CONDA_PREFIX` to make is useable in conda activate/deactivate scripts (#224) * Generate `pydoc` executable after creating new virtualenv (#197, #230) #### v1.1.0 * fish: use "set -gx" instead of "setenv" (#215, #216, #217, #218) #### v1.0.0 * Use similar versioning scheme as pyenv; YYYYMMDD -> X.Y.Z #### v20160716 * Suppress activate/deactivate messages by default (#169, #170, #171) * Source conda package activate/deactivat scripts if exist (#173) * Use `source` in favor of `.` for `fish` (#175) * Use `python -m venv` instead of `pyvenv` due to deprecation of `pyvenv` after 3.6 (#184, #185) #### v20160315 * Evaluate `${PATH}` when outputted code is eval'd. (#154) * Set proper `CONDA_DEFAULT_ENV` for shorter name (#160) #### v20160202 * Install virtualenv 13.1.2 for CPython/Stackless 3.2.x (yyuu/pyenv#531) #### v20160112 * Fix problem with `virtualenv` to look up executables from source version with `--system-site-packages` (#62) #### v20151229 * Fix `deactivate` error on `fish` (#136) #### v20151222 * Improved interoperability with Anaconda/Miniconda (#103, #106, #107, #108) * Create `virtualenv` inside `envs` directory of source version, like Anaconda/Miniconda (#103, #107) * Rewrite `pyenv activate` and `pyenv deactivate` without using scripts provided by virtualenv and conda (#51, #69, #103, #104, #121) * Improve the `pyenv activate` behaviour on multiple versions (#105, #111) * Reject creating a virtualenv named `system` (yyuu/pyenv#475) * Add `--skip-aliases` to `pyenv virtualenvs` (#120) * Stop showing `version not installed` warning messages in precmd (#49) #### v20151103 * Passing return value from executed command. (#100) * Add workaround for commands installed in a virtual environment created by `pyvenv` (#62) * init: zsh: prepend hook to `precmd_functions` (#101) #### v20151006 * Ignore user's site-packages on ensurepip/get-pip (#89) * Find `python-config` from source version if current version is a virtualenv * Fix pyenv-virtualenv-init script for fish where command was in string and not being evaluated (#98) * Add foolproof for `-p` argument. (yyuu/pyenv#98) #### v20150719 * Add support for `conda` environments created by Anaconda/Miniconda (#91) * Look up commands for original version as well if the environment is created with `--system-site-packages` (#62) * Add error message if the source version is not installed (#83) #### v20150526 * Use `typeset -g` with `precmd_functions` (#75) * activate: display setup instructions only with `PYENV_VIRTUALENV_INIT=0` (#78) * Ignore failure of pyenv activate (#68) #### v20150119 * Ignore errors from `pyenv-version-name` since it might fail if there is configuration error (yyuu/pyenv#291) * The _shell_ version set in `activate` should be unset in `deactivate` (#61) * Anaconda has `activate` script nevertheless it is not a virtual environment (#65) #### v20141106 * Stop creating after `ensurepip` since it has done by `ensurepip` itself * Suppress some useless warnings from `pyenv virtualenv-init` #### v20141012 * Fix warnings from `shellcheck` to improve support for POSIX sh (#40) * Do not allow whitespace in `VIRTUALENV_NAME` (#44) * Should not persist `PYENV_DEACTIVATE` after automatic deactivation (#47, #48) #### v20140705 * Display information on auto-(de)?activation * Support manual (de)?activation with auto-activation enabled (#32, #34) * Exit as error when (de)?activation failed * Use https://bootstrap.pypa.io/ to install setuptools and pip * Create backup of original virtualenv within `$(pyenv root)/versions` when `--upgrade` #### v20140615 * Fix incompatibility issue of `pyenv activate` and `pyenv deactivate` (#26) * Workaround for the issue with pyenv-which-ext (#26) #### v20140614 * Add `pyenv virtualenv-init` to enable auto-activation feature (#24) * Create symlinks for executables with version suffix (yyuu/pyenv#182) #### v20140602 * Use new style GH raw url to avoid redirects (raw.github.com -> raw.githubusercontent.com) * Repaired virtualenv activation and deactivation for the fish shell (#23) #### v20140421 * Display error if `pyenv activate` was invoked as a command * Fix completion of `pyenv activate` (#15) * Use `virtualenv` instead of `pyvenv` if `-p` has given (yyuu/pyenv#158) #### v20140123 * Add `activate` and `deactivate` to make `pyenv-virtualenv` work with [jedi](https://github.com/davidhalter/jedi) (#9) * Use `ensurepip` to install `pip` if it is available * Unset `PIP_REQUIRE_VENV` to avoid problem on the installation of `virtualenv` (#10) * Add tests #### v20140110.1 * Fix install script #### v20140110 * Support environment variables of `EZ_SETUP` and `GET_PIP`. * Support a short option `-p` of `virtualenv`. #### v20131216 * Use latest release of setuptools and pip if the version not given via environment variables. #### v20130622 * Removed bundled `virtualenv.py` script. Now pyenv-virtualenv installs `virtualenv` package into source version and then use it. * On Python 3.3+, use `pyvenv` as virtualenv command if `virtualenv` is not available. * Install setuptools and pip into environments created by `pyvenv`. #### v20130614 * Add `pyenv virtualenvs` to list all virtualenv versions. * *EXPERIMENTAL*: Add `--upgrade` option to re-create virtualenv with migrating packages #### v20130527 * Remove `python-virtualenv` which was no longer used. * Change the installation path of the `virtualenv.py` script. (`./libexec` -> `./libexec/pyenv-virtualenv/${VIRTUALENV_VERSION}`) * Download `virtualenv.py` if desired version has not been installed. #### v20130507 * Display virtualenv information in `--help` and `--version` * Update virtualenv version; 1.8.4 -> 1.9.1 #### v20130307 * Rename the project; `s/python-virtualenv/pyenv-virtualenv/g` * The `pyenv-virtualenv` script is not depending on `python-virtualenv` now. `python-virtualenv` will left for compatibility and will not continue for future releases. * Update virtualenv version; 1.8.2 -> 1.8.4 #### v20130218 * Add pyenv 0.2.x (rbenv 0.4.x) style help messages. #### v20121023 * Create virtualenv with exact name of python executables. * Changed command-line options of python-virtualenv. First argument should be a path to the python executable. * Add install script. #### v20120927 * Initial public release. ================================================ FILE: LICENSE ================================================ Copyright (c) 2025 Yamashita, Yuu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: MAINTENANCE.md ================================================ Creating a release ================== The release of the new version of Pyenv is done via GitHub Releases. Release checklist: * Start [drafting a new release on GitHub](https://github.com/pyenv/pyenv-virtualenv/releases) to generate a summary of changes. Save the summary locally. * 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) * Push the version number in `bin/pyenv-virtualenv` * Minor version is pushed if there are significant functional changes (not e.g. bugfixes/formula adaptations/supporting niche use cases). * Major version is pushed if there are breaking changes * 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 * Commit the changes locally into `master` * Create a new tag with the new version number and push the changes including the tag * Create a new release on GitHub based on the tag, using the saved summary ================================================ FILE: README.md ================================================ # pyenv-virtualenv [![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) [![Build Status](https://travis-ci.org/pyenv/pyenv-virtualenv.svg?branch=master)](https://travis-ci.org/pyenv/pyenv-virtualenv) pyenv-virtualenv is a [pyenv](https://github.com/pyenv/pyenv) plugin that provides features to manage virtualenvs and conda environments for Python on UNIX-like systems. (NOTICE: If you are an existing user of [virtualenvwrapper](http://pypi.python.org/pypi/virtualenvwrapper) and you love it, [pyenv-virtualenvwrapper](https://github.com/pyenv/pyenv-virtualenvwrapper) may help you (additionally) to manage your virtualenvs.) ## Installation ### Installing as a pyenv plugin This will install the latest development version of pyenv-virtualenv into the `$(pyenv root)/plugins/pyenv-virtualenv` directory. **Important note:** If you installed pyenv into a non-standard directory, make sure that you clone this repo into the 'plugins' directory of wherever you installed into. From inside that directory you can: - Check out a specific release tag. - Get the latest development release by running `git pull` to download the latest changes. 💡 **WSL note:** If you're using WSL, we recommend setting Git to use Unix-style line endings to prevent script execution errors: ```sh git config --global core.autocrlf input ``` 1. **Check out pyenv-virtualenv into plugin directory** ```bash git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv ``` For the Fish shell: ```fish git clone https://github.com/pyenv/pyenv-virtualenv.git (pyenv root)/plugins/pyenv-virtualenv ``` 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. ```bash echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc ``` **Fish shell note**: Add this to your `~/.config/fish/config.fish` ```fish status --is-interactive; and pyenv virtualenv-init - | source ``` **Zsh note**: Modify your `~/.zshrc` file instead of `~/.bashrc`. 3. **Restart your shell to enable pyenv-virtualenv** ```bash exec "$SHELL" ``` ### Installing with Homebrew (for macOS users) macOS users can install pyenv-virtualenv with the [Homebrew](https://brew.sh) package manager. This will give you access to the `pyenv-virtualenv` command. If you have pyenv installed, you will also be able to use the `pyenv virtualenv` command. *This is the recommended method of installation if you installed pyenv with Homebrew.* ```sh brew install pyenv-virtualenv ``` Or, if you would like to install the latest development release: ```sh brew install --HEAD pyenv-virtualenv ``` After installation, you'll still need to do [Pyenv shell setup steps](https://github.com/pyenv/pyenv#b-set-up-your-shell-environment-for-pyenv) then add ```sh eval "$(pyenv virtualenv-init -)" ``` to your shell's `.rc` file (as stated in the caveats). You'll only ever have to do this once. ## Usage ### Using `pyenv virtualenv` with pyenv To create a virtualenv for the Python version used with pyenv, run `pyenv virtualenv`, specifying the Python version you want and the name of the virtualenv directory. For example, ```sh pyenv virtualenv 2.7.10 my-virtual-env-2.7.10 ``` will create a virtualenv based on Python 2.7.10 under `$(pyenv root)/versions` in a folder called `my-virtual-env-2.7.10`. `pyenv virtualenv` forwards any options to the underlying command that actually creates the virtual environment (`conda`, `virtualenv`, or `python -m venv`). See the output of `pyenv virtualenv --help` for details. ### Create virtualenv from current version If there is only one argument given to `pyenv virtualenv`, the virtualenv will be created with the given name based on the current pyenv Python version. ```sh $ pyenv version 3.4.3 (set by /home/yyuu/.pyenv/version) $ pyenv virtualenv venv34 ``` ### List existing virtualenvs `pyenv virtualenvs` shows you the list of existing virtualenvs and `conda` environments. ```sh $ pyenv shell venv34 $ pyenv virtualenvs miniconda3-3.9.1 (created from /home/yyuu/.pyenv/versions/miniconda3-3.9.1) miniconda3-3.9.1/envs/myenv (created from /home/yyuu/.pyenv/versions/miniconda3-3.9.1) 2.7.10/envs/my-virtual-env-2.7.10 (created from /home/yyuu/.pyenv/versions/2.7.10) 3.4.3/envs/venv34 (created from /home/yyuu/.pyenv/versions/3.4.3) my-virtual-env-2.7.10 (created from /home/yyuu/.pyenv/versions/2.7.10) * venv34 (created from /home/yyuu/.pyenv/versions/3.4.3) ``` There are two entries for each virtualenv, and the shorter one is just a symlink. ### Activate virtualenv Some external tools (e.g. [jedi](https://github.com/davidhalter/jedi)) might require you to `activate` the virtualenv and `conda` environments. 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. You can also activate and deactivate a pyenv virtualenv manually: ```sh pyenv activate pyenv deactivate ``` ### Delete existing virtualenv Removing the directories in `$(pyenv root)/versions` and `$(pyenv root)/versions/{version}/envs` will delete the virtualenv, or you can run: ```sh pyenv uninstall my-virtual-env ``` You can also delete existing virtualenvs by using `virtualenv-delete` command, e.g. you can run: ```sh pyenv virtualenv-delete my-virtual-env ``` This will delete virtualenv called `my-virtual-env`. ### virtualenv and venv There is a [venv](http://docs.python.org/3/library/venv.html) module available for CPython 3.3 and newer. It provides an executable module `venv` which is the successor of `virtualenv` and distributed by default. `pyenv-virtualenv` uses `python -m venv` if it is available and the `virtualenv` command is not available. ### Anaconda and Miniconda You can manage `conda` environments by `conda create` as same manner as standard Anaconda/Miniconda installations. To use those environments, you can use `pyenv activate` and `pyenv deactivate`. ```sh $ pyenv version miniconda3-3.9.1 (set by /home/yyuu/.pyenv/version) $ conda env list # conda environments: # myenv /home/yyuu/.pyenv/versions/miniconda3-3.9.1/envs/myenv root * /home/yyuu/.pyenv/versions/miniconda3-3.9.1 $ pyenv activate miniconda3-3.9.1/envs/myenv discarding /home/yyuu/.pyenv/versions/miniconda3-3.9.1/bin from PATH prepending /home/yyuu/.pyenv/versions/miniconda3-3.9.1/envs/myenv/bin to PATH $ python --version Python 3.4.3 :: Continuum Analytics, Inc. $ pyenv deactivate discarding /home/yyuu/.pyenv/versions/miniconda3-3.9.1/envs/myenv/bin from PATH ``` If `conda` is available, `pyenv virtualenv` will use it to create environment by `conda create`. ```sh $ pyenv version miniconda3-3.9.1 (set by /home/yyuu/.pyenv/version) $ pyenv virtualenv myenv2 $ conda env list # conda environments: # myenv /home/yyuu/.pyenv/versions/miniconda3-3.9.1/envs/myenv myenv /home/yyuu/.pyenv/versions/miniconda3-3.9.1/envs/myenv2 root * /home/yyuu/.pyenv/versions/miniconda3-3.9.1 ``` You can use version like `miniconda3-3.9.1/envs/myenv` to specify `conda` environment as a version in pyenv. ```sh $ pyenv version miniconda3-3.9.1 (set by /home/yyuu/.pyenv/version) $ pyenv shell miniconda3-3.9.1/envs/myenv $ which python /home/yyuu/.pyenv/versions/miniconda3-3.9.1/envs/myenv/bin/python ``` ### Special environment variables You can set certain environment variables to control pyenv-virtualenv. * `PYENV_VIRTUALENV_CACHE_PATH`, if set, specifies a directory to use for caching downloaded package files. * `VIRTUALENV_VERSION`, if set, forces pyenv-virtualenv to install the desired version of virtualenv. If `virtualenv` has not been installed, pyenv-virtualenv will try to install the given version of virtualenv. * `GET_PIP`, if set and `venv` is preferred over `virtualenv`, use `get_pip.py` from the specified location. * `GET_PIP_URL`, if set and `venv` is preferred over `virtualenv`, download `get_pip.py` from the specified URL. * `PIP_VERSION`, if set and `venv` is preferred over `virtualenv`, install the specified version of pip. * `PYENV_VIRTUALENV_VERBOSE_ACTIVATE`, if set, shows some verbose outputs on activation and deactivation * `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})`. ## Version History See [CHANGELOG.md](CHANGELOG.md). ### License [(The MIT License)](LICENSE) * Copyright (c) 2015 Yamashita, Yuu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: bin/pyenv-activate ================================================ #!/usr/bin/env bash # # Summary: Activate virtual environment # # Usage: pyenv activate # pyenv activate --unset # # Activate a Python virtualenv environment in current shell. # This acts almost as same as `pyenv shell`, but this invokes the `activate` # script in your shell. # # should be a string matching a Python version known to pyenv. set -e [ -n "$PYENV_DEBUG" ] && set -x # Provide pyenv completions if [ "$1" = "--complete" ]; then echo --unset exec pyenv-virtualenvs --bare fi { printf "\x1B[31;1m" echo echo "\`pyenv activate' requires Pyenv and Pyenv-Virtualenv to be loaded into your shell." echo "Check your shell configuration and Pyenv and Pyenv-Virtualenv installation instructions." echo printf "\x1B[0m" } 1>&2 exit 1 ================================================ FILE: bin/pyenv-deactivate ================================================ #!/usr/bin/env bash # # Summary: Deactivate virtual environment # # Usage: pyenv deactivate # # Deactivate a Python virtual environment. set -e [ -n "$PYENV_DEBUG" ] && set -x { printf "\x1B[31;1m" echo echo "\`pyenv deactivate' requires Pyenv and Pyenv-Virtualenv to be loaded into your shell." echo "Check your shell configuration and Pyenv and Pyenv-Virtualenv installation instructions." echo printf "\x1B[0m" } 1>&2 exit 1 ================================================ FILE: bin/pyenv-sh-activate ================================================ #!/usr/bin/env bash # # Summary: Activate virtual environment # # Usage: pyenv activate # pyenv activate --unset # # Activate a Python virtualenv environment in current shell. # This acts almost as same as `pyenv shell`, but this invokes the `activate` # script in your shell. # # should be a string matching a Python version known to pyenv. set -e [ -n "$PYENV_DEBUG" ] && set -x if [ -z "${PYENV_ROOT}" ]; then PYENV_ROOT="$(pyenv-root)" fi resolve_link() { $(type -p greadlink readlink | head -1) "$1" } unset FORCE unset QUIET # Define `before_activate` and `after_activate` functions that allow # plugin hooks to register a string of code for execution before or # after activating a virtualenv. declare -a before_hooks after_hooks before_activate() { local hook="$1" before_hooks["${#before_hooks[@]}"]="$hook" } after_activate() { local hook="$1" after_hooks["${#after_hooks[@]}"]="$hook" } # Load plugin hooks. OLDIFS="$IFS" IFS=$'\n' scripts=(`pyenv-hooks activate`) IFS="$OLDIFS" for script in "${scripts[@]}"; do source "$script"; done while [ $# -gt 0 ]; do case "$1" in "--complete" ) # Provide pyenv completions echo --unset exec pyenv-virtualenvs --bare ;; "-f" | "--force" ) FORCE=1 ;; "-q" | "--quiet" ) QUIET=1 ;; "--unset" ) exec pyenv-sh-deactivate ;; "-v" | "--verbose" ) unset QUIET PYENV_VIRTUALENV_VERBOSE_ACTIVATE=1 ;; * ) break ;; esac shift 1 done get_current_versions() { local IFS=: current_versions=($(pyenv-version-name 2>/dev/null)) } no_shell= versions=("$@") current_versions=() if [ -z "${versions}" ]; then no_shell=1 get_current_versions versions=("${current_versions[@]}") fi if [ -z "${PYENV_VIRTUALENV_INIT}" ]; then # Backward compatibility issue # https://github.com/yyuu/pyenv-virtualenv/issues/26 no_shell= fi venv="${versions}" if [ -n "${VIRTUAL_ENV}" ]; then # exit as success if a non-pyenv virtualenv is active if [[ -z $PYENV_VIRTUAL_ENV || $PYENV_VIRTUAL_ENV != "$VIRTUAL_ENV" ]]; then if [ -z "${FORCE}" ]; then if [ -z "${QUIET}" ]; then echo "pyenv-virtualenv: virtualenv \`${VIRTUAL_ENV}' is already activated" 1>&2 fi echo "true" exit 0 fi fi fi if ! pyenv-virtualenv-prefix "${venv}" 1>/dev/null 2>&1; then # fallback to virtualenv of current version [ -n "${current_versions}" ] || get_current_versions new_venv="${current_versions%/envs/*}/envs/${venv}" if pyenv-virtualenv-prefix "${new_venv}" 1>/dev/null 2>&1; then venv="${new_venv}" versions[0]="${new_venv}" else if [ -z "${QUIET}" ]; then echo "pyenv-virtualenv: version \`${venv}' is not a virtualenv" 1>&2 fi echo "false" exit 1 fi fi # exit as error if there are multiple virtualenvs # https://github.com/yyuu/pyenv-virtualenv/issues/105 for version in "${versions[@]}"; do if [[ "${version}" != "${venv}" ]]; then if pyenv-virtualenv-prefix "${version}" 1>/dev/null 2>&1; then if [ -z "${QUIET}" ]; then echo "pyenv-virtualenv: cannot activate multiple versions at once: ${versions[@]}" 1>&2 fi echo "false" exit 1 fi fi done shell="${PYENV_SHELL:-${SHELL##*/}}" prefix="$(pyenv-prefix "${venv}")" if [ -L "${prefix}" ]; then prefix="$(resolve_link "${prefix}" 2>/dev/null)" fi # exit as success if the virtualenv is already activated if [[ "${VIRTUAL_ENV}" == "${prefix}" ]]; then if [ -z "${FORCE}" ]; then if [ -z "${QUIET}" ]; then echo "pyenv-virtualenv: version \`${venv}' is already activated" 1>&2 fi echo "true" exit 0 fi fi pyenv-sh-deactivate --force --quiet || true # Execute `before_activate` hooks. for hook in "${before_hooks[@]}"; do eval "$hook"; done if [ -n "$PYENV_VIRTUALENV_VERBOSE_ACTIVATE" ]; then echo "pyenv-virtualenv: activate ${venv}" 1>&2 fi if [ -z "$no_shell" ]; then # shell version set in pyenv-sh-activate should be unset # https://github.com/yyuu/pyenv-virtualenv/issues/61 OLDIFS="$IFS" IFS=: case "$shell" in fish ) cat <&2 fi echo "false" exit 1 fi fi shell="$(basename "${PYENV_SHELL:-$SHELL}")" prefix="${VIRTUAL_ENV}" if [[ "${prefix%/*/envs/*}" == "${PYENV_ROOT}/versions" ]]; then venv="${prefix#${PYENV_ROOT}/versions/}" else venv="${prefix##*/}" fi # Execute `before_deactivate` hooks. for hook in "${before_hooks[@]}"; do eval "$hook"; done if [ -n "$PYENV_VIRTUALENV_VERBOSE_ACTIVATE" ]; then echo "pyenv-virtualenv: deactivate ${venv}" 1>&2 fi # conda package anaconda/miniconda scripts (#173) if [ -d "${prefix}/conda-meta" ] || [ -x "${prefix}/bin/conda" ]; then shopt -s nullglob case "${shell}" in fish ) : # conda doesn't support fish ;; * ) for script in "${prefix}/etc/conda/deactivate.d"/*.sh; do echo ". \"${script}\";" done echo "unset CONDA_PREFIX" ;; esac shopt -u nullglob fi if [ -n "${PYENV_ACTIVATE_SHELL}" ]; then # shell version set in pyenv-sh-activate should be unset # https://github.com/yyuu/pyenv-virtualenv/issues/61 case "$shell" in fish ) cat </dev/null 2>&1; then unset -f deactivate; fi; EOS ;; esac # Execute `after_deactivate` hooks. for hook in "${after_hooks[@]}"; do eval "$hook"; done ================================================ FILE: bin/pyenv-virtualenv ================================================ #!/usr/bin/env bash # # Summary: Create a Python virtualenv using the pyenv-virtualenv plugin # # Usage: pyenv virtualenv [-f|--force] [VIRTUALENV_OPTIONS] [version] # pyenv virtualenv --version # pyenv virtualenv --help # # -f/--force Install even if the version appears to be installed already. Skip # prompting for confirmation # # Notable VIRTUALENV_OPTIONS passed to venv-creating executable, if applicable: # -u/--upgrade Imply --force # PYENV_VIRTUALENV_VERSION="1.2.6" set -e [ -n "$PYENV_DEBUG" ] && set -x if [ -z "${PYENV_ROOT}" ]; then PYENV_ROOT="$(pyenv-root)" fi # Provide pyenv completions if [ "$1" = "--complete" ]; then exec pyenv-versions --bare fi unset PIP_REQUIRE_VENV unset PIP_REQUIRE_VIRTUALENV # Define library functions parse_options() { OPTIONS=() ARGUMENTS=() local arg option index for arg in "$@"; do if [ "${arg:0:1}" = "-" ]; then if [ "${arg:1:1}" = "-" ]; then OPTIONS[${#OPTIONS[*]}]="${arg:2}" else index=1 while option="${arg:$index:1}"; do [ -n "$option" ] || break OPTIONS[${#OPTIONS[*]}]="$option" index=$(($index+1)) done fi else ARGUMENTS[${#ARGUMENTS[*]}]="$arg" fi done } colorize() { if [ -t 1 ]; then printf "\e[%sm%s\e[m" "$1" "$2" else echo -n "$2" fi } resolve_link() { $(type -p greadlink readlink | head -1) "$1" } abs_dirname() { local cwd="$(pwd)" local path="$1" while [ -n "$path" ]; do cd "${path%/*}" local name="${path##*/}" path="$(resolve_link "$name" || true)" done pwd cd "$cwd" } http() { local method="$1" local url="$2" local file="$3" [ -n "$url" ] || return 1 if type curl &>/dev/null; then "http_${method}_curl" "$url" "$file" elif type wget &>/dev/null; then "http_${method}_wget" "$url" "$file" else echo "error: please install \`curl\` or \`wget\` and try again" >&2 exit 1 fi } http_head_curl() { curl -qsILf "$1" >&4 2>&1 } http_get_curl() { curl -C - -o "${2:--}" -qsSLf "$1" } http_head_wget() { wget -q --spider "$1" >&4 2>&1 } http_get_wget() { wget -nv -c -O "${2:--}" "$1" } version() { if [[ -z "${PYENV_VERSION:-}" ]]; then # `PYENV_VERSION` might not be declared if this was invoked via `--version` export PYENV_VERSION="$(pyenv-version-name)" fi detect_venv local version if [ -n "${USE_CONDA}" ]; then version="$(pyenv-exec conda --version 2>/dev/null || true)" echo "pyenv-virtualenv ${PYENV_VIRTUALENV_VERSION} (conda ${version:-unknown})" else if [ -n "$USE_M_VENV" ]; then echo "pyenv-virtualenv ${PYENV_VIRTUALENV_VERSION} (${M_VENV_PYTHON_BIN:-python} -m venv)" else version="$(pyenv-exec virtualenv --version 2>/dev/null || true)" echo "pyenv-virtualenv ${PYENV_VIRTUALENV_VERSION} (virtualenv ${version:-unknown})" fi fi } usage() { # We can remove the sed fallback once pyenv 0.2.0 is widely available. pyenv-help virtualenv 2>/dev/null || sed -ne '/^#/!q;s/.//;s/.//;1,4d;p' < "$0" if [ -n "${USE_CONDA}" ]; then pyenv-exec conda create --help 2>/dev/null || true else if [ -n "${USE_M_VENV}" ]; then pyenv-exec "${M_VENV_PYTHON_BIN:-python}" -m venv --help 2>/dev/null || true else pyenv-exec virtualenv --help 2>/dev/null || true fi fi [ -z "$1" ] || exit "$1" } detect_venv() { # Check the existence of executables as a workaround for the issue with pyenv-which-ext # https://github.com/yyuu/pyenv-virtualenv/issues/26 local prefix="$(pyenv-prefix)" if [ -x "${prefix}/bin/conda" ]; then HAS_CONDA=1 else if [ -x "${prefix}/bin/virtualenv" ]; then HAS_VIRTUALENV=1 fi local python local -a pythons if [[ $PYENV_VERSION == "system" ]]; then # Prefer `python3.x` executable if available (#206, #282) pythons=("python3" "python" "python2") else # as per PEP 394, custom activated Python environments should provide the "python" command # this includes Pyenv-provided installations pythons=("python") fi for python in "${pythons[@]}"; do if pyenv-exec "${python}" -m venv --help 1>/dev/null 2>&1; then HAS_M_VENV=1 M_VENV_PYTHON_BIN="${python}" break fi done fi # Use `python -m venv` only if there is venv available, virtualenv is not installed, and `-p` not given if [ -n "${HAS_CONDA}" ]; then USE_CONDA=1 else if [ -n "${HAS_M_VENV}" ] && [ -z "${HAS_VIRTUALENV}" ] && [ -z "${VIRTUALENV_PYTHON}" ]; then USE_M_VENV=1 fi fi } build_package_ez_setup() { local ez_setup="${PYENV_VIRTUALENV_CACHE_PATH}/ez_setup.py" rm -f "${ez_setup}" { if [ "${EZ_SETUP+defined}" ] && [ -f "${EZ_SETUP}" ]; then echo "Installing setuptools from ${EZ_SETUP}..." 1>&2 cat "${EZ_SETUP}" else [ -n "${EZ_SETUP_URL}" ] echo "Installing setuptools from ${EZ_SETUP_URL}..." 1>&2 http get "${EZ_SETUP_URL}" fi } 1> "${ez_setup}" pyenv-exec python -s "${ez_setup}" ${EZ_SETUP_OPTS} 1>&2 || { echo "error: failed to install setuptools via ez_setup.py" >&2 return 1 } } build_package_get_pip() { local get_pip="${PYENV_VIRTUALENV_CACHE_PATH}/get-pip.py" rm -f "${get_pip}" { if [ "${GET_PIP+defined}" ] && [ -f "${GET_PIP}" ]; then echo "Installing pip from ${GET_PIP}..." 1>&2 cat "${GET_PIP}" else [ -n "${GET_PIP_URL}" ] echo "Installing pip from ${GET_PIP_URL}..." 1>&2 http get "${GET_PIP_URL}" fi } 1> "${get_pip}" pyenv-exec python -s "${get_pip}" ${GET_PIP_OPTS} 1>&2 || { echo "error: failed to install pip via get-pip.py" >&2 return 1 } } build_package_ensurepip() { pyenv-exec python -s -m ensurepip 2>/dev/null || build_package_get_pip "$@" || return 1 } prepare_requirements() { pyenv-exec pip freeze > "${REQUIREMENTS}" mv -f "${VIRTUALENV_PATH}" "${VIRTUALENV_ORIG}" } install_requirements() { if [ -f "${REQUIREMENTS}" ]; then ## Migrate previously installed packages from requirements.txt pyenv-exec pip install $QUIET $VERBOSE --requirement "${REQUIREMENTS}" || { echo echo "PIP INSTALL FAILED" echo echo "Inspect or clean up the original tree at ${VIRTUALENV_ORIG}" echo echo "Package list:" cat "${REQUIREMENTS}" | sed 's/^/ * /' return 1 } 1>&2 rm -f "${REQUIREMENTS}" rm -fr "${VIRTUALENV_ORIG}" fi } PYENV_VIRTUALENV_ROOT="$(abs_dirname "$0")/.." if [ -z "${PYENV_VIRTUALENV_CACHE_PATH}" ]; then PYENV_VIRTUALENV_CACHE_PATH="${PYTHON_BUILD_CACHE_PATH:-${PYENV_ROOT}/cache}" fi VIRTUALENV_OPTIONS=() unset FORCE unset NO_ENSUREPIP unset QUIET unset UPGRADE unset VERBOSE unset VIRTUALENV_PYTHON parse_options "$@" for option in "${OPTIONS[@]}"; do case "$option" in "f" | "force" ) FORCE=true ;; "h" | "help" ) usage 0 ;; "no-pip" ) NO_ENSUREPIP=1 VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="--$option" ;; "no-setuptools" ) NO_ENSUREPIP=1 VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="--$option" ;; "p" | "python" ) VIRTUALENV_PYTHON="${ARGUMENTS[0]}" ARGUMENTS=("${ARGUMENTS[@]:1}") # shift 1 ;; "q" | "quiet" ) QUIET="--quiet" ;; "u" | "upgrade" ) UPGRADE=true ;; "v" | "verbose" ) VERBOSE="--verbose" ;; "version" ) version exit 0 ;; "without-pip" ) NO_ENSUREPIP=1 VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="--$option" ;; * ) # virtualenv long options if [[ "$option" == "python="* ]]; then VIRTUALENV_PYTHON="${option#python=}" else VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="--$option" fi ;; esac done if [[ "${#ARGUMENTS[@]}" == 0 ]]; then echo "pyenv-virtualenv: no virtualenv name given." 1>&2 exit 1 elif [[ "${#ARGUMENTS[@]}" == 1 ]]; then # If only one argument given, use current version as source version OLDIFS="${IFS}" IFS=: VERSION_NAMES=($(pyenv-version-name)) IFS="${OLDIFS}" VERSION_NAME="${VERSION_NAMES}" VIRTUALENV_NAME="${ARGUMENTS[0]}" else # Otherwise, use former as source version, and latter as virtualenv version VERSION_NAME="${ARGUMENTS[0]}" VIRTUALENV_NAME="${ARGUMENTS[1]}" fi if [[ -n "${VERSION_NAME}" ]] && command -v pyenv-latest >/dev/null; then VERSION_NAME="$(pyenv-latest -f "${VERSION_NAME}")" fi if [ -z "${VERSION_NAME}" ] || [ -z "${VIRTUALENV_NAME}" ]; then usage 1 fi if [[ "${VIRTUALENV_NAME##*/}" == "system" ]]; then echo "pyenv-virtualenv: \`system' is not allowed as virtualenv name." 1>&2 exit 1 fi if [ "$VIRTUALENV_NAME" != "${VIRTUALENV_NAME%[[:space:]]*}" ]; then echo "pyenv-virtualenv: no whitespace allowed in virtualenv name." 1>&2 exit 1 fi if [ "${VIRTUALENV_NAME}" != "${VIRTUALENV_NAME%/*}" ] && [[ "${VIRTUALENV_NAME}" != "${VERSION_NAME%%/*}/envs/${VIRTUALENV_NAME##*/}" ]] ; then echo "pyenv-virtualenv: no slash allowed in virtualenv name." 1>&2 exit 1 fi # Set VERSION_NAME as default version in this script export PYENV_VERSION="${VERSION_NAME}" not_installed_message() { local is_available=$(python-build --definitions | grep -F -x "$1") echo "pyenv-virtualenv: \`${1}' is not installed in pyenv." 1>&2 if [[ $is_available ]]; then echo "Run \`pyenv install ${1}' to install it." 1>&2 else echo "It does not look like a valid Python version. See \`pyenv install --list' for available versions." 1>&2 fi } # Source version must exist before creating virtualenv. PREFIX="$(pyenv-prefix 2>/dev/null || true)" if [ ! -d "${PREFIX}" ]; then not_installed_message "${PYENV_VERSION}" exit 1 fi if [ -z "$TMPDIR" ]; then TMP="/tmp" else TMP="${TMPDIR%/}" fi # Not create `system/envs` directory even if source version is `system` if [[ "${VERSION_NAME%/envs/*}" == "system" ]]; then VIRTUALENV_NAME="${VIRTUALENV_NAME##*/}" else VIRTUALENV_PREFIX="$(pyenv-virtualenv-prefix 2>/dev/null || true)" if [[ "${VIRTUALENV_PREFIX%/*}" == "${PYENV_ROOT}/versions" ]]; then VIRTUALENV_NAME="${VIRTUALENV_PREFIX#${PYENV_ROOT}/versions/}/envs/${VIRTUALENV_NAME##*/}" else VIRTUALENV_NAME="${VERSION_NAME}/envs/${VIRTUALENV_NAME##*/}" fi fi VIRTUALENV_PATH="${PYENV_ROOT}/versions/${VIRTUALENV_NAME}" if [[ "${VIRTUALENV_PATH/*/envs/*}" != "${PYENV_ROOT}/versions" ]]; then COMPAT_VIRTUALENV_PATH="${PYENV_ROOT}/versions/${VIRTUALENV_NAME##*/}" fi if [ -n "${COMPAT_VIRTUALENV_PATH}" ]; then if [ -z ${FORCE} ]; then if [ -e "${COMPAT_VIRTUALENV_PATH}" ] || [ -L "${COMPAT_VIRTUALENV_PATH}" ]; then echo "pyenv-virtualenv: \`${COMPAT_VIRTUALENV_PATH}' already exists." 1>&2 exit 1 fi fi fi unset HAS_VIRTUALENV unset HAS_M_VENV unset USE_CONDA unset USE_M_VENV detect_venv SEED="$(date "+%Y%m%d%H%M%S").$$" VIRTUALENV_ORIG="${VIRTUALENV_PATH}.${SEED}" REQUIREMENTS="${TMP}/requirements.${SEED}.txt" # Upgrade existing virtualenv if [ -n "$UPGRADE" ]; then FORCE=1 # `python -m venv` has `--upgrade` by default if [ -n "${USE_M_VENV}" ]; then unset UPGRADE VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="--upgrade" fi fi if [ -z "${VIRTUALENV_VERSION}" ]; then case "${PYENV_VERSION}" in "3.0"* ) NO_ENSUREPIP=1 ;; "3.1"* ) NO_ENSUREPIP=1 ;; "3.2"* | "stackless-3.2"* ) # pip 8.x (bundled with virtualenv 14+) doesn't support 3.2 anymore # https://github.com/yyuu/pyenv/issues/531 VIRTUALENV_VERSION="13.1.2" NO_ENSUREPIP=1 ;; esac fi if [ -n "${USE_CONDA}" ]; then # e.g. `conda create -n py35 python=3.5 anaconda` if [ -n "${VIRTUALENV_PYTHON}" ]; then VIRTUALENV_PYTHON="${VIRTUALENV_PYTHON##*/}" VIRTUALENV_PYTHON="${VIRTUALENV_PYTHON#python}" if [ -n "${VIRTUALENV_PYTHON}" ]; then VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="python=${VIRTUALENV_PYTHON}" fi fi else if [ -n "${USE_M_VENV}" ]; then # Unset some arguments not supported by `python -m venv` unset QUIET unset VERBOSE if [ -n "${VIRTUALENV_PYTHON}" ]; then echo "pyenv-virtualenv: \`--python=${VIRTUALENV_PYTHON}' is not supported by \`python -m venv'." 1>&2 exit 1 fi else if [ -n "${VIRTUALENV_PYTHON}" ]; then if [[ "${VIRTUALENV_PYTHON}" == "${VIRTUALENV_PYTHON##*/}" ]] || [[ "${VIRTUALENV_PYTHON}" == "${PYENV_ROOT}/shims/"* ]]; then python="$(pyenv-which "${VIRTUALENV_PYTHON##*/}" 2>/dev/null || true)" if [ -x "${python}" ]; then VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="--python=${python}" else python="$(PYENV_VERSION="$(pyenv-whence "${VIRTUALENV_PYTHON##*/}" 2>/dev/null | tail -n 1 || true)" pyenv-which "${VIRTUALENV_PYTHON##*/}" 2>/dev/null || true)" if [ -x "${python}" ]; then VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="--python=${python}" else # echo "pyenv-virtualenv: \`${VIRTUALENV_PYTHON##*/}' is not installed in pyenv." 1>&2 not_installed_message "${VIRTUALENV_PYTHON##*/}" exit 1 fi fi else VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="--python=${VIRTUALENV_PYTHON}" fi fi if [ -z "${HAS_VIRTUALENV}" ]; then if [ -n "${VIRTUALENV_VERSION}" ]; then virtualenv_spec="virtualenv==${VIRTUALENV_VERSION}" else virtualenv_spec="virtualenv" fi pyenv-exec pip install $QUIET $VERBOSE "${virtualenv_spec}" HAS_VIRTUALENV=1 fi fi fi # Unset environment variables which start with `VIRTUALENV_`. # These variables are reserved for virtualenv. unset VIRTUALENV_VERSION # Download specified version of ez_setup.py/get-pip.py. if [ -z "${EZ_SETUP_URL}" ]; then if [ -n "${SETUPTOOLS_VERSION}" ]; then EZ_SETUP_URL="https://bitbucket.org/pypa/setuptools/raw/${SETUPTOOLS_VERSION}/ez_setup.py" unset SETUPTOOLS_VERSION else EZ_SETUP_URL="https://bootstrap.pypa.io/ez_setup.py" fi fi if [ -z "${GET_PIP_URL}" ]; then if [ -n "${PIP_VERSION}" ]; then { colorize 1 "WARNING" echo ": Setting PIP_VERSION=${PIP_VERSION} is no longer supported and may cause failures during the install process." } 1>&2 GET_PIP_URL="https://raw.githubusercontent.com/pypa/pip/${PIP_VERSION}/contrib/get-pip.py" # Unset `PIP_VERSION` from environment before invoking `get-pip.py` to deal with "ValueError: invalid truth value" (pypa/pip#4528) unset PIP_VERSION else # Use custom get-pip URL based on the target version (#1127) case "${PYENV_VERSION}" in 2.6 | 2.6.* ) GET_PIP_URL="https://bootstrap.pypa.io/pip/2.6/get-pip.py" ;; 2.7 | 2.7.* ) GET_PIP_URL="https://bootstrap.pypa.io/pip/2.7/get-pip.py" ;; 3.2 | 3.2.* ) GET_PIP_URL="https://bootstrap.pypa.io/pip/3.2/get-pip.py" ;; 3.3 | 3.3.* ) GET_PIP_URL="https://bootstrap.pypa.io/pip/3.3/get-pip.py" ;; 3.4 | 3.4.* ) GET_PIP_URL="https://bootstrap.pypa.io/pip/3.4/get-pip.py" ;; 3.5 | 3.5.* ) GET_PIP_URL="https://bootstrap.pypa.io/pip/3.5/get-pip.py" ;; 3.6 | 3.6.* ) GET_PIP_URL="https://bootstrap.pypa.io/pip/3.6/get-pip.py" ;; * ) GET_PIP_URL="https://bootstrap.pypa.io/pip/get-pip.py" ;; esac fi fi # Define `before_virtualenv` and `after_virtualenv` functions that allow # plugin hooks to register a string of code for execution before or # after the installation process. declare -a before_hooks after_hooks before_virtualenv() { local hook="$1" before_hooks["${#before_hooks[@]}"]="$hook" } after_virtualenv() { local hook="$1" after_hooks["${#after_hooks[@]}"]="$hook" } # Load plugin hooks. OLDIFS="$IFS" IFS=$'\n' scripts=(`pyenv-hooks virtualenv`) IFS="$OLDIFS" for script in "${scripts[@]}"; do source "$script"; done [ -d "${VIRTUALENV_PATH}" ] && PREFIX_EXISTS=1 # If the virtualenv exists, prompt for confirmation unless # the --force option was specified. if [ -d "${VIRTUALENV_PATH}/bin" ]; then if [ -z "$FORCE" ]; then echo "pyenv-virtualenv: ${VIRTUALENV_PATH} already exists" 1>&2 read -p "continue with installation? (y/N) " case "$REPLY" in y* | Y* ) ;; * ) exit 1 ;; esac fi if [ -n "$UPGRADE" ]; then if [ -n "${NO_ENSUREPIP}" ]; then echo "pyenv-virtualenv: upgrading will not work with --no-setuptools or --no-pip" 1>&2 exit 1 else PYENV_VERSION="${VIRTUALENV_NAME}" prepare_requirements fi fi fi # Execute `before_virtualenv` hooks. for hook in "${before_hooks[@]}"; do eval "$hook"; done # Plan cleanup on unsuccessful installation. cleanup() { [[ -L "${COMPAT_VIRTUALENV_PATH}" ]] && rm "${COMPAT_VIRTUALENV_PATH}" [ -z "${PREFIX_EXISTS}" ] && rm -rf "$VIRTUALENV_PATH" } trap cleanup SIGINT ERR # Invoke virtualenv and record exit status in $STATUS. STATUS=0 # virtualenv may download distribute/setuptools into the current directory. # Change to cache directory to reuse them between invocations. mkdir -p "${PYENV_VIRTUALENV_CACHE_PATH}" cd "${PYENV_VIRTUALENV_CACHE_PATH}" if [ -n "${USE_CONDA}" ]; then if [ -z "$VIRTUALENV_PYTHON" ]; then #process substitution doesn't seem to work unless it's directly inserted to the command line #if we add it to VIRTUALENV_OPTIONS instead, "broken pipe" happens pyenv-exec conda create $QUIET $VERBOSE --name "${VIRTUALENV_PATH##*/}" --yes "${VIRTUALENV_OPTIONS[@]}" --file <(pyenv-exec conda list python --full-name --export) || STATUS="$?" else pyenv-exec conda create $QUIET $VERBOSE --name "${VIRTUALENV_PATH##*/}" --yes "${VIRTUALENV_OPTIONS[@]}" || STATUS="$?" fi else if [ -n "${USE_M_VENV}" ]; then pyenv-exec "${M_VENV_PYTHON_BIN:-python}" -m venv $QUIET $VERBOSE "${VIRTUALENV_OPTIONS[@]}" "${VIRTUALENV_PATH}" || STATUS="$?" else pyenv-exec virtualenv $QUIET $VERBOSE "${VIRTUALENV_OPTIONS[@]}" "${VIRTUALENV_PATH}" || STATUS="$?" fi fi ( shopt -s nullglob for extra_binary in "$PREFIX"/bin/python*-config; do extra_binary_linkname="$VIRTUALENV_PATH/bin/$(basename $extra_binary)" [[ -e "$extra_binary_linkname" ]] || \ ln -s "$extra_binary" "$extra_binary_linkname" done ) ## Create symlink in the `versions` directory for backward compatibility if [ -d "${VIRTUALENV_PATH}" ] && [ -n "${COMPAT_VIRTUALENV_PATH}" ]; then # Overwrite an existing link, can happen if running with -f ln -fsn "${VIRTUALENV_PATH}" "${COMPAT_VIRTUALENV_PATH}" fi if [ ! -e "${VIRTUALENV_PATH}/bin/pydoc" ]; then mkdir -p "${VIRTUALENV_PATH}/bin" cat < "${VIRTUALENV_PATH}/bin/pydoc" #!${VIRTUALENV_PATH}/bin/python import pydoc if __name__ == '__main__': pydoc.cli() EOS chmod +x "${VIRTUALENV_PATH}/bin/pydoc" fi if [ -z "${NO_ENSUREPIP}" ]; then ## Install setuptools and pip. PYENV_VERSION="${VIRTUALENV_NAME}" build_package_ensurepip ## Migrate previously installed packages from requirements.txt. PYENV_VERSION="${VIRTUALENV_NAME}" install_requirements || true fi # Execute `after_virtualenv` hooks. for hook in "${after_hooks[@]}"; do eval "$hook"; done # Run `pyenv-rehash` after a successful installation. if [ "$STATUS" == "0" ]; then pyenv-rehash else cleanup fi exit "$STATUS" ================================================ FILE: bin/pyenv-virtualenv-delete ================================================ #!/usr/bin/env bash # # Summary: Uninstall a specific Python virtualenv # # Usage: pyenv virtualenv-delete [-f|--force] # # -f Attempt to remove the specified virtualenv without prompting # for confirmation. If the virtualenv does not exist, do not # display an error message. # # See `pyenv virtualenvs` for a complete list of installed versions. # set -e [ -n "$PYENV_DEBUG" ] && set -x if [ -z "${PYENV_ROOT}" ]; then PYENV_ROOT="$(pyenv-root)" fi # Provide pyenv completions if [ "$1" = "--complete" ]; then exec pyenv virtualenvs --bare fi resolve_link() { $(type -p greadlink readlink | head -1) "$1" } usage() { pyenv-help virtualenv-delete 2>/dev/null [ -z "$1" ] || exit "$1" } if [ -z "$PYENV_ROOT" ]; then PYENV_ROOT="${HOME}/.pyenv" fi if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then usage 0 fi unset FORCE if [ "$1" = "-f" ] || [ "$1" = "--force" ]; then FORCE=true shift fi [ "$#" -eq 1 ] || usage 1 >&2 DEFINITION="$1" case "$DEFINITION" in "" | -* ) usage 1 >&2 ;; esac VERSION_NAME="${DEFINITION##*/}" # Must initialize because it might be set in the environment ENV_PREFIX= ENV_COMPAT_PREFIX="${PYENV_ROOT}/versions/${VERSION_NAME}" if [[ "${DEFINITION}" != "${DEFINITION%/envs/*}" ]]; then ENV_PREFIX="${PYENV_ROOT}/versions/${DEFINITION}" if [ -L "${ENV_COMPAT_PREFIX}" ]; then if [[ "${ENV_PREFIX}" != "$(resolve_link "${ENV_COMPAT_PREFIX}" 2>/dev/null || true)" ]]; then unset ENV_COMPAT_PREFIX fi fi else if [ -L "${ENV_COMPAT_PREFIX}" ]; then ENV_PREFIX="$(resolve_link "${ENV_COMPAT_PREFIX}" 2>/dev/null || true)" if [[ "${ENV_PREFIX%/*/envs/*}" != "${PYENV_ROOT}/versions" ]]; then echo "pyenv-virtualenv: \`${ENV_COMPAT_PREFIX}' is a symlink for unknown location." 1>&2 exit 1 fi else if pyenv-virtualenv-prefix "${VERSION_NAME}" 1>/dev/null 2>&1; then ENV_PREFIX="${PYENV_ROOT}/versions/${VERSION_NAME}" unset ENV_COMPAT_PREFIX elif [ -z "$FORCE" ]; then echo "pyenv-virtualenv: \`${DEFINITION}' is not a virtualenv." 1>&2 exit 1 fi fi fi if [ ! -d "$ENV_PREFIX" ]; then if [ -z "$FORCE" ]; then echo "pyenv-virtualenv: virtualenv \`$VERSION_NAME' not installed" >&2 exit 1 else exit 0 fi fi if [ -z "$FORCE" ]; then read -p "pyenv-virtualenv: remove $ENV_PREFIX? (y/N) " case "$REPLY" in y* | Y* ) ;; * ) exit 1 ;; esac fi rm -rf "$ENV_PREFIX" if [ -L "$ENV_COMPAT_PREFIX" ]; then rm -rf "$ENV_COMPAT_PREFIX" fi pyenv-rehash ================================================ FILE: bin/pyenv-virtualenv-init ================================================ #!/usr/bin/env bash # Summary: Configure the shell environment for pyenv-virtualenv # Usage: eval "$(pyenv virtualenv-init - [])" # # Automatically activates a Python virtualenv environment based on current # pyenv version. # set -e [ -n "$PYENV_DEBUG" ] && set -x resolve_link() { $(type -p greadlink readlink | head -1) "$1" } abs_dirname() { local cwd="$(pwd)" local path="$1" while [ -n "$path" ]; do cd "${path%/*}" local name="${path##*/}" path="$(resolve_link "$name" || true)" done pwd cd "$cwd" } PYENV_VIRTUALENV_INSTALL_PREFIX="$(dirname "$(abs_dirname "$0")")" print="" for args in "$@" do if [ "$args" = "-" ]; then print=1 shift fi done shell="${1:-$PYENV_SHELL}" if [ -z "$shell" ]; then shell="$(ps -p "$PPID" -o 'args=' 2>/dev/null || true)" shell="${shell##-}" shell="${shell%% *}" shell="${shell:-$SHELL}" shell="${shell##*/}" shell="${shell%%-*}" fi if [ -z "$print" ]; then case "$shell" in bash ) profile='~/.bashrc' ;; zsh ) profile='~/.zshrc' ;; ksh ) profile='~/.profile' ;; fish ) profile='~/.config/fish/config.fish' ;; * ) profile='your profile' ;; esac { echo "# Load pyenv-virtualenv automatically by adding" echo "# the following to ${profile}:" echo case "$shell" in fish ) echo 'status --is-interactive; and source (pyenv virtualenv-init -|psub)' ;; * ) echo 'eval "$(pyenv virtualenv-init -)"' ;; esac echo } >&2 exit 1 fi case "$shell" in fish ) cat <] # set -e [ -n "$PYENV_DEBUG" ] && set -x if [ -L "${BASH_SOURCE}" ]; then READLINK=$(type -p greadlink readlink | head -1) if [ -z "$READLINK" ]; then echo "pyenv: cannot find readlink - are you missing GNU coreutils?" >&2 exit 1 fi resolve_link() { $READLINK -f "$1" } script_path=$(resolve_link ${BASH_SOURCE}) else script_path=${BASH_SOURCE} fi . ${script_path%/*}/../libexec/pyenv-virtualenv-realpath if [ -z "$PYENV_ROOT" ]; then PYENV_ROOT="${HOME}/.pyenv" fi if [ -n "$1" ]; then versions=($@) IFS=: PYENV_VERSION="${versions[*]}" export PYENV_VERSION else IFS=: versions=($(pyenv-version-name)) fi append_virtualenv_prefix() { if [ -d "${VIRTUALENV_PREFIX_PATH}" ]; then VIRTUALENV_PREFIX_PATHS=("${VIRTUALENV_PREFIX_PATHS[@]}" "${VIRTUALENV_PREFIX_PATH:-${PYENV_PREFIX_PATH}}") else echo "pyenv-virtualenv: version \`${version}' is not a virtualenv" 1>&2 exit 1 fi } VIRTUALENV_PREFIX_PATHS=() for version in "${versions[@]}"; do if [ "$version" = "system" ]; then echo "pyenv-virtualenv: version \`${version}' is not a virtualenv" 1>&2 exit 1 fi PYENV_PREFIX_PATH="$(pyenv-prefix "${version}")" if [ -x "${PYENV_PREFIX_PATH}/bin/python" ]; then if [ -f "${PYENV_PREFIX_PATH}/bin/activate" ]; then if [ -f "${PYENV_PREFIX_PATH}/bin/conda" ]; then # conda VIRTUALENV_PREFIX_PATH="${PYENV_PREFIX_PATH}" else if [ -f "${PYENV_ROOT}/versions/${version}/pyvenv.cfg" ]; then # venv virtualenv_binpath="$(cut -b 1-1024 "${PYENV_ROOT}/versions/${version}/pyvenv.cfg" | sed -n '/^ *home *= */s///p' || true)" VIRTUALENV_PREFIX_PATH="${virtualenv_binpath%/bin}" else # virtualenv if [ -d "${PYENV_ROOT}/versions/${version}/Lib" ]; then # jython virtualenv_libpath="${PYENV_ROOT}/versions/${version}/Lib" else if [ -d "${PYENV_ROOT}/versions/${version}/lib-python" ]; then # pypy virtualenv_libpath="${PYENV_ROOT}/versions/${version}/lib-python" else virtualenv_libpath="${PYENV_ROOT}/versions/${version}/lib" fi fi virtualenv_orig_prefix="$(find "${virtualenv_libpath}/" -maxdepth 2 -type f -and -name "orig-prefix.txt" 2>/dev/null | head -1)" if [ -f "${virtualenv_orig_prefix}" ]; then VIRTUALENV_PREFIX_PATH="$(cat "${virtualenv_orig_prefix}" 2>/dev/null || true)" fi fi fi append_virtualenv_prefix elif [ -d "${PYENV_PREFIX_PATH}/conda-meta" ]; then # conda VIRTUALENV_PREFIX_PATH="$(realpath "${PYENV_PREFIX_PATH}"/../..)" append_virtualenv_prefix else echo "pyenv-virtualenv: version \`${version}' is not a virtualenv" 1>&2 exit 1 fi else echo "pyenv-virtualenv: \`python' not found in version \`${version}'" 1>&2 exit 1 fi done IFS=: echo "${VIRTUALENV_PREFIX_PATHS[*]}" ================================================ FILE: bin/pyenv-virtualenvs ================================================ #!/usr/bin/env bash # # Summary: List all Python virtualenvs found in `$PYENV_ROOT/versions/*'. # Usage: pyenv virtualenvs [--bare] [--skip-aliases] # # List all virtualenvs found in `$PYENV_ROOT/versions/*' and its `$PYENV_ROOT/versions/envs/*'. set -e [ -n "$PYENV_DEBUG" ] && set -x if [ -L "${BASH_SOURCE}" ]; then READLINK=$(type -p greadlink readlink | head -1) if [ -z "$READLINK" ]; then echo "pyenv: cannot find readlink - are you missing GNU coreutils?" >&2 exit 1 fi resolve_link() { $READLINK -f "$1" } script_path=$(resolve_link ${BASH_SOURCE}) else script_path=${BASH_SOURCE} fi . ${script_path%/*}/../libexec/pyenv-virtualenv-realpath if [ -z "$PYENV_ROOT" ]; then PYENV_ROOT="${HOME}/.pyenv" fi unset bare unset skip_aliases # Provide pyenv completions for arg; do case "$arg" in --complete ) echo --bare echo --skip-aliases exit ;; --bare ) bare=1 ;; --skip-aliases ) skip_aliases=1 ;; * ) pyenv-help --usage virtualenvs >&2 exit 1 ;; esac done versions_dir="${PYENV_ROOT}/versions" if [ -d "$versions_dir" ]; then versions_dir="$(realpath "$versions_dir")" fi if [ -n "$bare" ]; then hit_prefix="" miss_prefix="" current_versions=() unset print_origin include_system="" else hit_prefix="* " miss_prefix=" " OLDIFS="$IFS" IFS=: current_versions=($(pyenv-version-name || true)) IFS="$OLDIFS" print_origin="1" include_system="" fi num_versions=0 exists() { local car="$1" local cdar shift for cdar in "$@"; do if [ "${car}" == "${cdar}" ]; then return 0 fi done return 1 } print_version() { if exists "$1" "${current_versions[@]}"; then echo "${hit_prefix}${1}${print_origin+$2}" else echo "${miss_prefix}${1}${print_origin+$2}" fi num_versions=$((num_versions + 1)) } shopt -s dotglob shopt -s nullglob for path in "$versions_dir"/*; do if [ -d "$path" ]; then if [ -n "$skip_aliases" ] && [ -L "$path" ]; then target="$(realpath "$path")" [ "${target%/*/envs/*}" != "$versions_dir" ] || continue fi virtualenv_prefix="$(pyenv-virtualenv-prefix "${path##*/}" 2>/dev/null || true)" if [ -d "${virtualenv_prefix}" ]; then print_version "${path##*/}" " (created from ${virtualenv_prefix})" fi for venv_path in "${path}/envs/"*; do venv="${path##*/}/envs/${venv_path##*/}" virtualenv_prefix="$(pyenv-virtualenv-prefix "${venv}" 2>/dev/null || true)" if [ -d "${virtualenv_prefix}" ]; then print_version "${venv}" " (created from ${virtualenv_prefix})" fi done fi done shopt -u dotglob shopt -u nullglob if [ "$num_versions" -eq 0 ] && [ -n "$include_system" ]; then echo "Warning: no Python virtualenv detected on the system" >&2 exit 1 fi ================================================ FILE: etc/pyenv.d/rehash/envs.bash ================================================ virtualenv_list_executable_names() { local file shopt -s nullglob for file in "$PYENV_ROOT"/versions/*/envs/*/bin/*; do echo "${file##*/}" done shopt -u nullglob } if declare -f make_shims 1>/dev/null 2>&1; then make_shims $(virtualenv_list_executable_names | sort -u) fi ================================================ FILE: etc/pyenv.d/uninstall/envs.bash ================================================ resolve_link() { $(type -p greadlink readlink | head -1) "$1" } uninstall_related_virtual_env() { if [ -n "${DEFINITION}" ]; then if [[ "${DEFINITION}" != "${DEFINITION%/envs/*}" ]]; then # Uninstall virtualenv by long name pyenv-virtualenv-delete ${FORCE+-f} "${DEFINITION}" else VERSION_NAME="${VERSION_NAME:-${DEFINITION##*/}}" PREFIX="${PREFIX:-${PYENV_ROOT}/versions/${VERSION_NAME}}" if [ -L "${PREFIX}" ]; then REAL_PREFIX="$(resolve_link "${PREFIX}" 2>/dev/null || true)" REAL_DEFINITION="${REAL_PREFIX#${PYENV_ROOT}/versions/}" if [[ "${REAL_DEFINITION}" != "${REAL_DEFINITION%/envs/*}" ]]; then # Uninstall virtualenv by short name pyenv-virtualenv-delete ${FORCE+-f} "${REAL_DEFINITION}" fi else # Uninstall all virtualenvs inside `envs` directory too shopt -s nullglob for virtualenv in "${PREFIX}/envs/"*; do pyenv-virtualenv-delete ${FORCE+-f} "${DEFINITION}/envs/${virtualenv##*/}" done shopt -u nullglob fi fi fi } before_uninstall "uninstall_related_virtual_env" ================================================ FILE: etc/pyenv.d/which/conda.bash ================================================ # newer versions of conda share programs from the real prefix # this hook tries to find the executable there if [ ! -x "${PYENV_COMMAND_PATH}" ] && [[ "${PYENV_COMMAND_PATH##*/}" == "conda" ]]; then if [ -d "${PYENV_ROOT}/versions/${version}/conda-meta" ]; then conda_command_path="$(pyenv-virtualenv-prefix "$version")"/bin/"${PYENV_COMMAND_PATH##*/}" if [ -x "${conda_command_path}" ]; then PYENV_COMMAND_PATH="${conda_command_path}" fi fi fi ================================================ FILE: etc/pyenv.d/which/python-config.bash ================================================ # some of libraries require `python-config` in PATH to build native extensions. # as a workaround, this hook will try to find the executable from the source # version of the virtualenv. # https://github.com/yyuu/pyenv/issues/397 if [ ! -x "${PYENV_COMMAND_PATH}" ] && [[ "${PYENV_COMMAND_PATH##*/}" == "python"*"-config" ]]; then OLDIFS="${IFS}" IFS=: version="$(pyenv-version-name)" IFS="${OLDIFS}" if [ -f "${PYENV_ROOT}/versions/${version}/bin/activate" ]; then if [ -f "${PYENV_ROOT}/versions/${version}/bin/conda" ]; then : # do nothing for conda's environments else if [ -f "${PYENV_ROOT}/versions/${version}/pyvenv.cfg" ]; then # venv virtualenv_binpath="$(cut -b 1-1024 "${PYENV_ROOT}/versions/${version}/pyvenv.cfg" | sed -n '/^ *home *= */s///p' || true)" virtualenv_prefix="${virtualenv_binpath%/bin}" else # virtualenv if [ -d "${PYENV_ROOT}/versions/${version}/Lib" ]; then # jython virtualenv_libpath="${PYENV_ROOT}/versions/${version}/Lib" else if [ -d "${PYENV_ROOT}/versions/${version}/lib-python" ]; then # pypy virtualenv_libpath="${PYENV_ROOT}/versions/${version}/lib-python" else virtualenv_libpath="${PYENV_ROOT}/versions/${version}/lib" fi fi virtualenv_orig_prefix="$(find "${virtualenv_libpath}/" -maxdepth 2 -type f -and -name "orig-prefix.txt" 2>/dev/null | head -1)" if [ -f "${virtualenv_orig_prefix}" ]; then virtualenv_prefix="$(cat "${virtualenv_orig_prefix}" 2>/dev/null || true)" fi fi virtualenv_command_path="${virtualenv_prefix}/bin/${PYENV_COMMAND_PATH##*/}" if [ -x "${virtualenv_command_path}" ]; then PYENV_COMMAND_PATH="${virtualenv_command_path}" fi fi fi fi ================================================ FILE: etc/pyenv.d/which/system-site-packages.bash ================================================ # if virtualenv is created with `--system-site-packages`, # looks up executables for source version as well if none is # installed in the virtualenv. # https://github.com/yyuu/pyenv-virtualenv/issues/62 if [ ! -x "${PYENV_COMMAND_PATH}" ]; then OLDIFS="${IFS}" IFS=: version="$(pyenv-version-name)" IFS="${OLDIFS}" if [ -f "${PYENV_ROOT}/versions/${version}/bin/activate" ]; then unset include_system_site_packages if [ -f "${PYENV_ROOT}/versions/${version}/bin/conda" ]; then : # do nothing for conda's environments else if [ -f "${PYENV_ROOT}/versions/${version}/pyvenv.cfg" ]; then # venv virtualenv_binpath="$(cut -b 1-1024 "${PYENV_ROOT}/versions/${version}/pyvenv.cfg" | sed -n '/^ *home *= */s///p' || true)" virtualenv_prefix="${virtualenv_binpath%/bin}" if grep -q -i "include-system-site-packages *= *true" "${PYENV_ROOT}/versions/${version}/pyvenv.cfg" 1>/dev/null 2>&1; then include_system_site_packages=1 fi else # virtualenv if [ -d "${PYENV_ROOT}/versions/${version}/Lib" ]; then # jython virtualenv_libpath="${PYENV_ROOT}/versions/${version}/Lib" else if [ -d "${PYENV_ROOT}/versions/${version}/lib-python" ]; then # pypy virtualenv_libpath="${PYENV_ROOT}/versions/${version}/lib-python" else virtualenv_libpath="${PYENV_ROOT}/versions/${version}/lib" fi fi no_global_site_packages="$(find "${virtualenv_libpath}/" -maxdepth 2 -type f -and -name "no-global-site-packages.txt" 2>/dev/null | head -1)" if [ ! -f "${no_global_site_packages}" ]; then include_system_site_packages=1 fi virtualenv_orig_prefix="$(find "${virtualenv_libpath}/" -maxdepth 2 -type f -and -name "orig-prefix.txt" 2>/dev/null | head -1)" if [ -f "${virtualenv_orig_prefix}" ]; then virtualenv_prefix="$(cat "${virtualenv_orig_prefix}" 2>/dev/null || true)" fi fi if [ -n "${include_system_site_packages}" ] && [ -n "${virtualenv_prefix}" ]; then # virtualenv is created with `--system-site-packages` virtualenv_command_path="${virtualenv_prefix}/bin/${PYENV_COMMAND_PATH##*/}" if [ -x "${virtualenv_command_path}" ]; then PYENV_COMMAND_PATH="${virtualenv_command_path}" fi fi fi fi fi ================================================ FILE: install.sh ================================================ #!/bin/sh # Usage: PREFIX=/usr/local ./install.sh # # Installs pyenv-virtualenv under $PREFIX. set -e cd "$(dirname "$0")" if [ -z "${PREFIX}" ]; then PREFIX="/usr/local" fi BIN_PATH="${PREFIX}/bin" LIBEXEC_PATH="${PREFIX}/libexec" SHIMS_PATH="${PREFIX}/shims" HOOKS_PATH="${PREFIX}/etc/pyenv.d" mkdir -p "$BIN_PATH" mkdir -p "$LIBEXEC_PATH" mkdir -p "$SHIMS_PATH" mkdir -p "$HOOKS_PATH" install -p bin/* "$BIN_PATH" install -p libexec/* "$LIBEXEC_PATH" install -p shims/* "$SHIMS_PATH" for hook in etc/pyenv.d/*; do if [ -d "$hook" ]; then cp -RPp "$hook" "$HOOKS_PATH" else install -p -m 0644 "$hook" "$HOOKS_PATH" fi done ================================================ FILE: libexec/pyenv-virtualenv-realpath ================================================ #!/usr/bin/env bash # Summary: Substitute realpath if unavailable as a builtin or file # Usage: . pyenv-virtualenv-realpath if ! { enable -f "${BASH_SOURCE%/*}"/../../../libexec/pyenv-realpath.dylib realpath || type realpath } >/dev/null 2>&1; then if [ -n "$PYENV_NATIVE_EXT" ]; then echo "pyenv: failed to load \`realpath' builtin" >&2 exit 1 fi READLINK=$(type -p greadlink readlink | head -1) if [ -z "$READLINK" ]; then echo "pyenv: cannot find readlink - are you missing GNU coreutils?" >&2 exit 1 fi resolve_link() { $READLINK "$1" } realpath() { local f="$*" \ name dir [[ $f ]] || { >&2 echo ${FUNCNAME[0]}: missing operand return } while [[ -L $f ]]; do f="$(resolve_link "$f")" done if [[ ! -d $f ]]; then name="/${f##*/}" # parent? dir="${f%/*}" if [[ $dir == $f ]]; then #lacks /: parent is current directory f="$PWD" else f="$dir" fi fi #absolute directory dir="$(cd "$f" pwd)" echo "$dir$name" } fi ================================================ FILE: shims/activate ================================================ #!/usr/bin/env bash if [[ "$0" != "${BASH_SOURCE}" ]]; then eval "$(pyenv sh-activate --verbose "$@" || true)" else echo "pyenv-virtualenv: activate must be sourced. Run 'source activate envname' instead of 'activate envname'" 1>&2 false fi ================================================ FILE: shims/deactivate ================================================ #!/usr/bin/env bash if [[ "$0" != "${BASH_SOURCE}" ]]; then eval "$(pyenv sh-deactivate --verbose "$@" || true)" else echo "pyenv-virtualenv: deactivate must be sourced. Run 'source deactivate' instead of 'deactivate'" 1>&2 false fi ================================================ FILE: test/activate.bats ================================================ #!/usr/bin/env bats load test_helper setup() { export HOME="${TMP}" export PYENV_ROOT="${TMP}/pyenv" unset PYENV_VERSION unset PYENV_ACTIVATE_SHELL unset VIRTUAL_ENV unset CONDA_DEFAULT_ENV unset PYTHONHOME unset _OLD_VIRTUAL_PYTHONHOME unset PYENV_VIRTUALENV_VERBOSE_ACTIVATE unset PYENV_VIRTUALENV_DISABLE_PROMPT unset PYENV_VIRTUAL_ENV_DISABLE_PROMPT unset VIRTUAL_ENV_DISABLE_PROMPT unset PYENV_VIRTUALENV_PROMPT unset _OLD_VIRTUAL_PS1 stub pyenv-hooks "activate : echo" } @test "activate virtualenv from current version" { export PYENV_VIRTUALENV_INIT=1 stub pyenv-version-name "echo venv" stub pyenv-virtualenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\"" stub pyenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\"" stub pyenv-sh-deactivate "--force --quiet : echo deactivated" PYENV_SHELL="bash" PYENV_VERSION="venv" run pyenv-sh-activate assert_success assert_output </dev/null 2>&1; then unset -f deactivate; fi; EOS teardown_conda "anaconda-2.3.0" } @test "deactivate conda root (fish)" { export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/anaconda-2.3.0" export VIRTUAL_ENV="${PYENV_ROOT}/versions/anaconda-2.3.0" export PYENV_ACTIVATE_SHELL= export CONDA_DEFAULT_ENV="root" setup_conda "anaconda-2.3.0" PYENV_SHELL="fish" run pyenv-sh-deactivate assert_success assert_output </dev/null 2>&1; then unset -f deactivate; fi; EOS teardown_conda "anaconda-2.3.0" "foo" } ================================================ FILE: test/conda-prefix.bats ================================================ #!/usr/bin/env bats load test_helper setup() { export PYENV_ROOT="${TMP}/pyenv" } @test "display conda root" { setup_conda "anaconda-2.3.0" stub pyenv-version-name "echo anaconda-2.3.0" stub pyenv-prefix "anaconda-2.3.0 : echo \"${PYENV_ROOT}/versions/anaconda-2.3.0\"" PYENV_VERSION="anaconda-2.3.0" run pyenv-virtualenv-prefix assert_success assert_output </dev/null 2>&1; then unset -f deactivate; fi; EOS } @test "deactivate virtualenv (quiet)" { export PYENV_VIRTUALENV_INIT=1 export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" export PYENV_ACTIVATE_SHELL= PYENV_SHELL="bash" run pyenv-sh-deactivate --quiet assert_success assert_output </dev/null 2>&1; then unset -f deactivate; fi; EOS } @test "deactivate virtualenv (verbose)" { export PYENV_VIRTUALENV_INIT=1 export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" export PYENV_ACTIVATE_SHELL= export PYENV_VIRTUALENV_VERBOSE_ACTIVATE=1 PYENV_SHELL="bash" run pyenv-sh-deactivate --verbose assert_success assert_output </dev/null 2>&1; then unset -f deactivate; fi; EOS } @test "deactivate virtualenv (with shell activation)" { export PYENV_VIRTUALENV_INIT=1 export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" export PYENV_ACTIVATE_SHELL=1 PYENV_SHELL="bash" run pyenv-sh-deactivate assert_success assert_output </dev/null 2>&1; then unset -f deactivate; fi; EOS } @test "deactivate virtualenv (with shell activation) (quiet)" { export PYENV_VIRTUALENV_INIT=1 export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" export PYENV_ACTIVATE_SHELL=1 PYENV_SHELL="bash" run pyenv-sh-deactivate --quiet assert_success assert_output </dev/null 2>&1; then unset -f deactivate; fi; EOS } @test "deactivate virtualenv which has been activated manually" { export PYENV_VIRTUALENV_INIT=1 export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" export PYENV_ACTIVATE_SHELL= PYENV_SHELL="bash" run pyenv-sh-deactivate assert_success assert_output </dev/null 2>&1; then unset -f deactivate; fi; EOS } @test "deactivate virtualenv (fish)" { export PYENV_VIRTUALENV_INIT=1 export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv" export PYENV_ACTIVATE_SHELL= PYENV_SHELL="fish" run pyenv-sh-deactivate assert_success assert_output < "${HOOK_PATH}/virtualenv.bash" < "${HOOK_PATH}/activate.bash" < "${HOOK_PATH}/deactivate.bash" </dev/null 2>&1; then unset -f deactivate; fi; after EOS unstub pyenv-hooks } ================================================ FILE: test/init.bats ================================================ #!/usr/bin/env bats load test_helper @test "detect parent shell" { unset PYENV_SHELL SHELL=/bin/false run pyenv-virtualenv-init - assert_success assert_output_contains ' PROMPT_COMMAND="_pyenv_virtualenv_hook;${PROMPT_COMMAND-}"' } @test "detect parent shell from script (sh)" { unset PYENV_SHELL printf '#!/bin/sh\necho "$(pyenv-virtualenv-init -)"' > "${TMP}/script.sh" chmod +x ${TMP}/script.sh run ${TMP}/script.sh assert_success assert_output_contains_not ' PROMPT_COMMAND="_pyenv_virtualenv_hook;${PROMPT_COMMAND-}"' rm -f "${TMP}/script.sh" } @test "detect parent shell from script (bash)" { unset PYENV_SHELL printf '#!/bin/bash\necho "$(pyenv-virtualenv-init -)"' > "${TMP}/script.sh" chmod +x ${TMP}/script.sh run ${TMP}/script.sh assert_success assert_output_contains ' PROMPT_COMMAND="_pyenv_virtualenv_hook;${PROMPT_COMMAND-}"' rm -f "${TMP}/script.sh" } @test "sh-compatible instructions" { run pyenv-virtualenv-init bash assert [ "$status" -eq 1 ] assert_output_contains 'eval "$(pyenv virtualenv-init -)"' run pyenv-virtualenv-init zsh assert [ "$status" -eq 1 ] assert_output_contains 'eval "$(pyenv virtualenv-init -)"' } @test "fish instructions" { run pyenv-virtualenv-init fish assert [ "$status" -eq 1 ] assert_output_contains 'status --is-interactive; and source (pyenv virtualenv-init -|psub)' } @test "outputs bash-specific syntax" { export PYENV_VIRTUALENV_ROOT="${TMP}/pyenv/plugins/pyenv-virtualenv" run pyenv-virtualenv-init - bash assert_success assert_output < "${PYENV_ROOT}/versions/$1/lib/python${2:-$1}/orig-prefix.txt" touch "${PYENV_ROOT}/versions/$1/bin/activate" } create_virtualenv_jython() { create_version "$1" create_version "${2:-$1}" mkdir -p "${PYENV_ROOT}/versions/$1/Lib/" echo "${PYENV_ROOT}/versions/${2:-$1}" > "${PYENV_ROOT}/versions/$1/Lib/orig-prefix.txt" touch "${PYENV_ROOT}/versions/$1/bin/activate" } create_virtualenv_pypy() { create_version "$1" create_version "${2:-$1}" mkdir -p "${PYENV_ROOT}/versions/$1/lib-python/${2:-$1}" echo "${PYENV_ROOT}/versions/${2:-$1}" > "${PYENV_ROOT}/versions/$1/lib-python/${2:-$1}/orig-prefix.txt" touch "${PYENV_ROOT}/versions/$1/bin/activate" } remove_virtualenv() { remove_version "$1" remove_version "${2:-$1}" } create_m_venv() { create_version "$1" create_version "${2:-$1}" echo "home = ${PYENV_ROOT}/versions/${2:-$1}/bin" > "${PYENV_ROOT}/versions/$1/pyvenv.cfg" touch "${PYENV_ROOT}/versions/$1/bin/activate" } remove_m_venv() { remove_version "${2:-$1}" } create_conda() { create_version "$1" create_version "${2:-$1}" touch "${PYENV_ROOT}/versions/$1/bin/conda" touch "${PYENV_ROOT}/versions/$1/bin/activate" mkdir -p "${PYENV_ROOT}/versions/${2:-$1}/bin" touch "${PYENV_ROOT}/versions/${2:-$1}/bin/conda" touch "${PYENV_ROOT}/versions/${2:-$1}/bin/activate" } remove_conda() { remove_version "${2:-$1}" } @test "display prefix of virtualenv created by virtualenv" { stub pyenv-version-name "echo foo" stub pyenv-prefix "foo : echo \"${PYENV_ROOT}/versions/foo\"" create_virtualenv "foo" "2.7.11" PYENV_VERSION="foo" run pyenv-virtualenv-prefix assert_success assert_output <"$STUB_LOCKFILE" ) 2>/dev/null && acquired=1 if [[ -n $acquired ]]; then trap release_lock EXIT break else # POSIX sleep(1) doesn't provide subsecond precision, but many others do sleep 0.1 2>/dev/null || sleep 1 fi done if [[ -z $acquired ]]; then echo "$0: error: could not acquire stub lock \`$STUB_LOCKFILE' in ${acquire_timeout} seconds" >&2 exit 2 fi } acquire_lock if [[ -z $STUB_END ]]; then echo "$program" "$@" >>"$STUB_LOG"; fi [[ -e $STUB_PLAN ]] || exit 1 # Initialize or load the stub run information. read_runfile() { if [[ -e $STUB_RUN ]]; then source "$STUB_RUN"; fi } write_runfile() { { local i echo "STUB_INDEX=$STUB_INDEX" echo "STUB_RESULT=$STUB_RESULT" echo "STUB_RUNCOUNTS=()" for i in ${!STUB_RUNCOUNTS[@]}; do echo "STUB_RUNCOUNTS[$i]=${STUB_RUNCOUNTS[$i]}" done } > "$STUB_RUN" } update_runfile_index() { ( STUB_INDEX=$((STUB_INDEX + 1)) write_runfile ) } update_runfile_result() { ( # Another stubs may have run while we were running payload # So we need to merge possible state changes local our_result="$STUB_RESULT" local -a our_runcounts array_copy STUB_RUNCOUNTS our_runcounts read_runfile # merge our match_result and their match_result, with failure taking precedence STUB_RESULT=$(( our_result | STUB_RESULT )) # 3-way merge STUB_RUNCOUNTS (their changes), # our_runcounts (our changes) and initial_runcounts (base) local i for i in $(printf '%s\n' ${!STUB_RUNCOUNTS[@]} ${!our_runcounts[@]} | sort -u); do STUB_RUNCOUNTS[$i]=$((STUB_RUNCOUNTS[i] + our_runcounts[i] - initial_runcounts[i])) done write_runfile ) } array_copy() { #`declare -p' is supposed to produce "declare -a src=([index]="value" )" local data="$(declare -p ${1:?})" local dest="${2:?}" # Bash 5 dumps empty arrays as "declare -a arr" if [[ $data != *=* ]]; then data="()"; else data="${data#*=}" fi # Bash 3 and MacPorts version of Bash 5 dump arrays in single quotes "declare -a arr='()'" # but arr='()' createss "([0]='')" rather than duplicate the array if [[ ${data:0:1} == "'" && ${data:${#data}-1:1} == "'" ]]; then data="${data:1:${#data}-2}" fi eval "$dest=$data" } STUB_INDEX=1 STUB_RESULT=0 declare -a STUB_RUNCOUNTS read_runfile declare -a initial_runcounts array_copy STUB_RUNCOUNTS initial_runcounts # ${PROGRAM}_STUB_END envvar is set externally to trigger verification mode for `unstub' # Execution mode if [[ -z $STUB_END ]]; then # Loop over each line in the plan. regular_command_index=0 no_order_command_index=0 match_result=1 while IFS= read -r line; do line_flags="${line%% *}" line="${line#${line_flags} }" line_flag_no_order="$(if [[ $line_flags == N ]]; then echo 1; fi)" line_flag_multiple="$(if [[ $line_flags == M ]]; then echo 1; fi)" line_flag_regular="$(if [[ $line_flags == - ]]; then echo 1; fi)" unset line_flags # Go through the plan until a match is found. # For regular commands, only check the next command by index. # Also keep track of no-order commands for the purpose of run count tracking if [[ -n $line_flag_regular ]]; then regular_command_index=$(($regular_command_index + 1)) if [[ $regular_command_index -ne $STUB_INDEX ]]; then continue; fi else no_order_command_index=$(($no_order_command_index + 1)) fi # Split the line into an array of arguments to # match and a command to run to produce output. command=" $line" if [[ $command == *" : "* ]]; then patterns="${command%% : *}" command="${command#* : }" fi # Naively split patterns by whitespace for now. # In the future, use a sed script to split while # respecting quoting. set -f patterns=($patterns) set +f arguments=("$@") # Match the expected argument patterns to actual # arguments. match_result=0 for (( i=0; i<${#patterns[@]}; i++ )); do pattern="${patterns[$i]}" argument="${arguments[$i]}" case "$argument" in $pattern ) ;; * ) match_result=1 ;; esac done # If the arguments matched, evaluate the command # in a subshell. Otherwise, log the failure. if [ $match_result -eq 0 ] ; then # If this is a regular command, push the regular command index for the next stub invocation if [[ -n $line_flag_regular ]]; then update_runfile_index else STUB_RUNCOUNTS[$no_order_command_index]=$((STUB_RUNCOUNTS[no_order_command_index]+1)) fi # Release the lock while running the payload to allow another `stub' # of the same program to run concurrently (e.g. in a pipeline). release_lock ( eval "$command" ) && status="$?" || status="$?" break fi done < "$STUB_PLAN" #If we never matched anything, we failed. if [[ $match_result -eq 1 ]]; then STUB_RESULT=1 #This also means that we never released the lock # before running the payload else acquire_lock fi # Write out the match_result information. update_runfile_result release_lock exit "$status" fi # Verification mode (`unstub') if [[ -n $STUB_END ]]; then # `unstub' is supposed to run after any stubs are finished release_lock # If the number of regular commands in the plan is larger than # the final regular_command_index, we failed. if [[ $(grep -Ee '^-' "$STUB_PLAN" | wc -l ) -ge $STUB_INDEX ]]; then STUB_RESULT=1 fi # If no-order commands weren't executed exactly once # and multiple-times commands at least once, we failed. no_order_command_index=0 while IFS= read -r line; do line_flags="${line%% *}" line="${line#${line_flags} }" line_flag_no_order="$(if [[ $line_flags == N ]]; then echo 1; fi)" line_flag_multiple="$(if [[ $line_flags == M ]]; then echo 1; fi)" line_flag_regular="$(if [[ $line_flags == - ]]; then echo 1; fi)" unset line_flags if [[ -z $line_flag_regular ]]; then continue fi no_order_command_index=$((no_order_command_index + 1)) if [[ ( -n $line_flag_no_order && \ (( STUB_RUNCOUNTS[no_order_command_index] != 1 )) ) \ || \ ( -n $line_flag_multiple && \ (( STUB_RUNCOUNTS[no_order_command_index] < 1 )) ) ]] then STUB_RESULT=1 fi done < "$STUB_PLAN" if [[ $STUB_RESULT -ne 0 ]]; then { echo "plan:" cat "$STUB_PLAN" || true echo "log:" cat "$STUB_LOG" || true } >&2 fi # Clean up the run file. rm -f "$STUB_RUN" rm -f "$STUB_LOG" # Return the run result. exit "$STUB_RESULT" fi ================================================ FILE: test/test_helper.bash ================================================ export TMP="$BATS_TEST_DIRNAME/tmp" export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' PATH=/usr/bin:/usr/sbin:/bin:/sbin PATH="$BATS_TEST_DIRNAME/../bin:$PATH" PATH="$TMP/bin:$PATH" export PATH teardown() { rm -fr "$TMP"/* } stub() { local FLAG_NO_ORDER= local FLAG_MULTIPLE= while (($#)); do case "$1" in -N|--no-order) FLAG_NO_ORDER=1 shift ;; -M|--multiple) FLAG_MULTIPLE=1 shift ;; -*) echo "stub: unrecognized switch: $arg" >$2 return 1 ;; *) break ;; esac done local FLAGS=- if [[ -n $FLAG_MULTIPLE ]]; then FLAGS=M elif [[ -n $FLAG_NO_ORDER ]]; then FLAGS=N fi local program="$1" local prefix="$(echo "$program" | tr a-z- A-Z_)" shift export "${prefix}_STUB_PLAN"="${TMP}/${program}-stub-plan" export "${prefix}_STUB_RUN"="${TMP}/${program}-stub-run" export "${prefix}_STUB_LOG"="${TMP}/${program}-stub-log" export "${prefix}_STUB_END"= mkdir -p "${TMP}/bin" ln -sf "${BATS_TEST_DIRNAME}/stubs/stub" "${TMP}/bin/${program}" touch "${TMP}/${program}-stub-plan" for arg in "$@"; do echo "$FLAGS" "$arg" >> "${TMP}/${program}-stub-plan" done } unstub() { local program="$1" local prefix="$(echo "$program" | tr a-z- A-Z_)" local path="${TMP}/bin/${program}" export "${prefix}_STUB_END"=1 local STATUS=0 "$path" || STATUS="$?" rm -f "$path" rm -f "${TMP}/${program}-stub-plan" "${TMP}/${program}-stub-run" return "$STATUS" } assert() { if ! "$@"; then flunk "failed: $@" fi } flunk() { { if [ "$#" -eq 0 ]; then cat - else echo "$@" fi } | sed "s:${TMP}:\${TMP}:g" >&2 return 1 } assert_success() { if [ "$status" -ne 0 ]; then { echo "command failed with exit status $status" echo "output: $output" } | flunk elif [ "$#" -gt 0 ]; then assert_output "$1" fi } assert_failure() { if [ "$status" -eq 0 ]; then flunk "expected failed exit status" elif [ "$#" -gt 0 ]; then assert_output "$1" fi } assert_equal() { if [ "$1" != "$2" ]; then { echo "expected:" echo "$1" echo "actual:" echo "$2" } | flunk fi } assert_equal_wildcards() { if [[ $1 != $2 ]]; then { echo "expected:" echo "$2" echo "actual:" echo "$1" } | flunk fi } assert_output() { local expected if [ $# -eq 0 ]; then expected="$(cat -)" else expected="$1" fi assert_equal "$expected" "$output" } assert_output_wildcards() { local expected if [ $# -eq 0 ]; then expected="$(cat -)" else expected="$1" fi assert_equal_wildcards "$output" "$expected" } assert_output_contains() { local expected="$1" echo "$output" | grep -F "$expected" >/dev/null || { { echo "expected output to contain $expected" echo "actual: $output" } | flunk } } assert_output_contains_not() { local expected="$1" echo "$output" | grep -F "$expected" >/dev/null && { { echo "expected output to not contain $expected" echo "actual: $output" } | flunk; return } return 0 } create_executable() { mkdir -p "${PYENV_ROOT}/versions/$1/bin" touch "${PYENV_ROOT}/versions/$1/bin/$2" chmod +x "${PYENV_ROOT}/versions/$1/bin/$2" } remove_executable() { rm -f "${PYENV_ROOT}/versions/$1/bin/$2" } setup_version() { create_executable "$1" "python" remove_executable "$1" "activate" remove_executable "$1" "conda" } teardown_version() { rm -fr "${PYENV_ROOT}/versions/$1" } setup_virtualenv() { create_executable "$1" "python" create_executable "$1" "activate" remove_executable "$1" "conda" } teardown_virtualenv() { rm -fr "${PYENV_ROOT}/versions/$1" } setup_m_venv() { create_executable "$1" "python" create_executable "$1" "activate" remove_executable "$1" "conda" } teardown_m_venv() { rm -fr "${PYENV_ROOT}/versions/$1" } setup_conda() { create_executable "$1" "python" create_executable "$1" "activate" create_executable "$1" "conda" local conda="$1" shift 1 local env for env; do create_executable "${conda}/envs/${env}" "python" create_executable "${conda}/envs/${env}" "activate" create_executable "${conda}/envs/${env}" "conda" mkdir -p "${PYENV_ROOT}/versions/${conda}/envs/${env}/etc/conda/activate.d" touch "${PYENV_ROOT}/versions/${conda}/envs/${env}/etc/conda/activate.d/activate.sh" mkdir -p "${PYENV_ROOT}/versions/${conda}/envs/${env}/etc/conda/deactivate.d" touch "${PYENV_ROOT}/versions/${conda}/envs/${env}/etc/conda/deactivate.d/deactivate.sh" done } teardown_conda() { rm -fr "${PYENV_ROOT}/versions/$1" } ================================================ FILE: test/version.bats ================================================ #!/usr/bin/env bats load test_helper setup() { export PYENV_ROOT="${TMP}/pyenv" } @test "display virtualenv version" { setup_virtualenv "2.7.7" stub pyenv-prefix "echo '${PYENV_ROOT}/versions/2.7.7'" stub pyenv-version-name "echo 2.7.7" stub pyenv-exec "python -m venv --help : false" stub pyenv-exec "virtualenv --version : echo \"1.11\"" run pyenv-virtualenv --version assert_success [[ "$output" == "pyenv-virtualenv "?.?.?" (virtualenv 1.11)" ]] unstub pyenv-prefix unstub pyenv-exec teardown_virtualenv "2.7.7" } @test "display venv version" { setup_m_venv "3.4.1" stub pyenv-version-name "echo 3.4.1" stub pyenv-prefix "echo '${PYENV_ROOT}/versions/3.4.1'" stub pyenv-exec "python -m venv --help : true" run pyenv-virtualenv --version assert_success [[ "$output" == "pyenv-virtualenv "?.?.?" (python -m venv)" ]] unstub pyenv-prefix teardown_m_venv "3.4.1" } ================================================ FILE: test/virtualenv.bats ================================================ #!/usr/bin/env bats load test_helper setup() { export PYENV_ROOT="${TMP}/pyenv" } stub_pyenv() { setup_version "${PYENV_VERSION}" create_executable "${PYENV_VERSION}" "virtualenv" stub pyenv-prefix "echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'" stub pyenv-prefix "echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'" stub pyenv-hooks "virtualenv : echo" stub pyenv-rehash " : echo rehashed" } unstub_pyenv() { unstub pyenv-prefix unstub pyenv-hooks unstub pyenv-rehash teardown_version "${PYENV_VERSION}" } @test "create virtualenv from given version" { export PYENV_VERSION="2.7.11" stub_pyenv "${PYENV_VERSION}" stub pyenv-virtualenv-prefix " : false" stub pyenv-exec "python -m venv --help : false" stub pyenv-exec "virtualenv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\"; mkdir -p \"\$2/bin\"" stub pyenv-exec "python -s -m ensurepip : false" stub pyenv-exec "python -s */get-pip.py : true" stub curl true create_executable "${PYENV_VERSION}" "python-config" create_executable "${PYENV_VERSION}" "python2-config" create_executable "${PYENV_VERSION}" "python2.7-config" run pyenv-virtualenv "2.7.11" "venv" assert_output <