Compare commits

...

50 commits

Author SHA1 Message Date
Ivan Pozdeev eda64556af
1.4.0
Some checks failed
tests / tests (ubuntu-22.04) (push) Has been cancelled
tests / tests (ubuntu-24.04) (push) Has been cancelled
tests / tests (macos-14) (push) Has been cancelled
tests / tests (macos-15) (push) Has been cancelled
tests / tests (macos-15-intel) (push) Has been cancelled
tests / tests (macos-26) (push) Has been cancelled
2026-04-29 08:24:00 +03:00
Sam Doran 37ab83f1b0
Improve performance and output of pyenv virtualenvs (#502)
* With 160 envs, cuts time from ~14s to ~2.5s
* Change the output to be more like `pyenv-versions'
* Shellcheck fixes
* virtualenv: Only show non-envs for completion since env engines don't support piggy-backing envs
* Remove dead/unused code
* Fix IFS handling
`IFS=: <command>' doesn't apply that IFS to expansions in <command>,
it has to be set separately earlier
* Adjust and refactor tests

---------

Co-authored-by: Ivan Pozdeev <vano@mail.mipt.ru>
2026-04-29 08:08:52 +03:00
Chris Caldwell 99d35f201c
Fix POSIX sh (dash) compatibility in pyenv-virtualenv-init (#526)
* Refactor cache code generation
* Don't generate prompt_command for non bash/zsh/fish

---------

Co-authored-by: Ivan Pozdeev <vano@mail.mipt.ru>
2026-04-21 18:53:01 +03:00
Ivan Pozdeev 6a832cacbb
CI: use macos-26
the Github runner is out of beta
2026-04-17 22:54:31 +03:00
Ivan Pozdeev 90dfbcad93
1.3.0 2026-03-25 23:46:29 +03:00
Ivan Pozdeev f046752219
Reformat changelog to conform to Pyenv and Github release notes 2026-03-25 23:45:47 +03:00
Jake Lodwick 72cb35b2b4
Drastically speed up precommand hook by caching active version to skip redundant activate calls (#523) 2026-03-25 23:33:43 +03:00
native-api 38f3333f3a
Merge pull request #520 from native-api/prevent-deletion-of-contents-in-generic-prefix-env-var
CI: tests: use Bats 1.10; support concurrent, out-of-order and multiple-times execution of stub commands; fix race condition between concurrent stubs
2025-12-18 03:52:21 +03:00
Ivan Pozdeev 10c8ace3c3
Fix a race condition between concurrently executing stubs 2025-12-18 03:47:17 +03:00
Ivan Pozdeev 7d9840478c
stub: -unnecessary indirection 2025-12-18 03:47:16 +03:00
Ivan Pozdeev bf7d3b0584
stub, test_helper: support concurrent, out-of-order and multiple-times stub command execution 2025-12-18 03:46:38 +03:00
Ivan Pozdeev dd2ad3ee65
stub: dumping the plan vars is redundant
They proved to not be useful for diagnostics
2025-12-18 03:30:05 +03:00
Ivan Pozdeev 4785e89a3b
Use Bats v1.10.0 2025-12-18 03:06:38 +03:00
native-api b83e2c3c83
CI: - commented-out code; - macos-11 workaround (#521) 2025-12-18 00:41:30 +03:00
Ivan Pozdeev b5c88a7a15
1.2.6 2025-12-14 18:41:47 +03:00
SabriRamadanTNG 64233612fb
Prevent loss of data on virtualenv-delete -f if the env doesn't exist and the PREFIX envvar is set elsewhere (#518)
* Rename the PREFIX var just in case as too generic

Co-authored-by: Ivan Pozdeev <vano@mail.mipt.ru>
2025-12-13 20:05:26 +03:00
native-api 4d37a6e477
Convert issue template to new Github format (#519)
* Convert issue template to new Github format

the old format seems to be dropped altogether now

[no ci]
2025-12-13 17:19:41 +03:00
Ivan Pozdeev f5b2602597
CI: change macos-13 to macos-15-intel 2025-12-11 14:47:13 +03:00
Charlie (cshen.dev) 387f627464
docs: fix the link to Pyenv shell setup steps (#516) 2025-09-22 08:36:00 +03:00
Seokhee Park 4b3f5f8468
docs: add WSL note about core.autocrlf to prevent CRLF issues (#512) 2025-05-17 10:19:25 +03:00
Ivan Pozdeev 3057e1549b [CI] Update environments
ubuntu-20.04 is dropped, macos-15 is available
2025-05-06 19:14:54 +03:00
Jason N. White aa9b8e9a5a
Update LICENSE, fix license year (#499)
Some checks failed
tests / tests (ubuntu-22.04) (push) Failing after 1s
tests / tests (macos-13) (push) Has been cancelled
tests / tests (macos-14) (push) Has been cancelled
tests / tests (ubuntu-20.04) (push) Has been cancelled
Signed-off-by: JasonnnW3000 <sufssl04@gmail.com>
2025-01-01 20:46:21 +03:00
native-api e8c8fd9b84
Fix errorneously creating a symlink inside env directory if running with -f (#496)
Some checks failed
tests / tests (macos-13) (push) Has been cancelled
tests / tests (macos-14) (push) Has been cancelled
tests / tests (ubuntu-20.04) (push) Has been cancelled
tests / tests (ubuntu-22.04) (push) Failing after 0s
2024-12-08 23:30:27 +03:00
native-api db299cada3
Fix confusing activate/deactivate error messages (#495) 2024-12-08 21:43:35 +03:00
native-api c6bb0694bf
Fix pyenv-virtualenv using a different Python version in a conda environment (#492)
Some checks failed
tests / tests (ubuntu-22.04) (push) Failing after 0s
tests / tests (macos-13) (push) Has been cancelled
tests / tests (macos-14) (push) Has been cancelled
tests / tests (ubuntu-20.04) (push) Has been cancelled
Allow output checking with wildcards
2024-11-25 00:54:05 +03:00
Zac Holland 28cd9be54e
README: fix and distinguish syntax highlighting in Bash vs Fish snippets (#489)
Some checks failed
tests / tests (ubuntu-22.04) (push) Failing after 0s
tests / tests (macos-13) (push) Has been cancelled
tests / tests (macos-14) (push) Has been cancelled
tests / tests (ubuntu-20.04) (push) Has been cancelled
Co-authored-by: native-api <vano@mail.mipt.ru>
2024-09-18 22:08:52 +03:00
Jovier Jimenez d4c9655e26
Add prompt customization (#476)
Some checks failed
tests / tests (ubuntu-22.04) (push) Failing after 1s
tests / tests (macos-13) (push) Has been cancelled
tests / tests (macos-14) (push) Has been cancelled
tests / tests (ubuntu-20.04) (push) Has been cancelled
2024-09-15 09:40:44 +03:00
Ivan Pozdeev e9b88cc366 1.2.4
Some checks failed
tests / tests (ubuntu-22.04) (push) Failing after 1s
tests / tests (macos-13) (push) Has been cancelled
tests / tests (macos-14) (push) Has been cancelled
tests / tests (ubuntu-20.04) (push) Has been cancelled
2024-07-22 00:37:02 +03:00
native-api d811b3fef2
Merge pull request #484 from native-api/pyenv_latest_f
Reflect pyenv-latest switch change in 2.4.8
2024-07-22 00:34:28 +03:00
Ivan Pozdeev d6756cab9b CI: bump macos
Github dropped macos-11, introduced 13 and 14
2024-07-22 00:32:59 +03:00
Ivan Pozdeev 6179ac76c4 Reflect pyenv-latest switch change in 2.4.8 2024-07-21 23:31:47 +03:00
Alex Galonsky cf45718a1b
README: Remove dollar signs from commands that are meant to be copied (#481)
Some checks failed
tests / tests (ubuntu-22.04) (push) Has been cancelled
tests / tests (macos-11) (push) Has been cancelled
tests / tests (macos-12) (push) Has been cancelled
tests / tests (ubuntu-20.04) (push) Has been cancelled
2024-06-27 20:16:45 +03:00
native-api 37917069ec
Fix failing to detect -m venv when "python" is not provided by the distro (#479) 2024-04-10 00:14:13 +03:00
Ivan Pozdeev b90bd92853 1.2.3 2024-04-07 22:59:10 +03:00
Ivan Pozdeev 33f54ecad9 Add maintenance guide 2024-04-07 22:50:45 +03:00
native-api f8469a1c67
Merge pull request #478 from native-api/3drparty_venv_over_ours
Don't activate if a 3rd-party venv is activated over ours
2024-04-03 23:12:47 +03:00
Ivan Pozdeev ac28398fc0 Don't activate if a 3rd-party virtualenv is active over ours 2024-04-03 21:09:22 +03:00
Ivan Pozdeev 45a28ac094 bump stub and stub fns to Pyenv version 2024-04-03 21:09:22 +03:00
Romir K 0f83c33a3b
Add fish prompt changing (#475) 2024-02-12 12:58:27 +03:00
John HU 2b2b87a25a
Bump pyenv-virtualenv reporting version to match release (#471)
The latest release so far (Dec 2023) is 1.2.2, but the version reported is still 1.2.1:
https://github.com/pyenv/pyenv-virtualenv/releases/tag/v1.2.2
2023-12-06 06:56:52 +03:00
Jason Mobarak 38a6561f96
fix: add colorize helper (#470) 2023-11-29 11:37:00 +03:00
native-api c85c1c9ed5
Link python*-config into VE (#460)
Required to build binaries that link against Python.
Carl Meyer, the champion for PEP 0405, has confirmed that there isn't a particular reason why `venv` doesn't do that.
2023-06-27 01:36:04 +03:00
Elijah Lynn cd6a51ad68
Add fish install oneliner (#322)
Co-authored-by: Ivan Pozdeev <vano@mail.mipt.ru>
2023-04-17 00:01:19 +03:00
Marcin Konowalczyk 85d8c5aabf
More helpful error message when env's base version is not installed (#454) 2023-04-10 21:42:47 +03:00
Josh French fca12418ca
Add activate/deactivate hooks (#452) 2023-03-22 20:39:55 +03:00
Jack McIvor 13bc1877ef
Update PYENV_VIRTUALENV_VERSION (#449)
Co-authored-by: Jack McIvor <j.mcivor@draftkings.com>
2023-02-07 19:37:47 +03:00
Ivan Pozdeev a724aaa149 Merge branch 'master' of https://github.com/pyenv/pyenv-virtualenv 2023-02-01 00:27:32 +03:00
Ivan Pozdeev f4162706d8 Remove Bountysource from advertized donation sources
Same as in Pyenv, as it's gone rogue
2023-02-01 00:27:13 +03:00
native-api 77a7644ff7
Remove prompt deprecation warning (#447)
Prompt removal was never done and is not planned anymore
2023-01-31 23:14:52 +03:00
Ivan Pozdeev 826f3fbe6f ISSUE_TEMPLATE.md: Add Zsh PS4 2023-01-31 23:02:54 +03:00
35 changed files with 1482 additions and 436 deletions

2
.github/FUNDING.yml vendored
View file

@ -9,4 +9,4 @@ community_bridge: # Replace with a single Community Bridge project-name e.g., cl
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: ['https://www.bountysource.com/teams/pyenv-virtualenv/issues'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View file

@ -1,17 +1,30 @@
Too many issues will kill our team's development velocity, drastically.
Make sure you have checked all steps below.
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
### Prerequisite
* [ ] Make sure your problem is not listed in [the common build problems](https://github.com/pyenv/pyenv/wiki/Common-build-problems).
* [ ] 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 not asking us to help solving your specific issue.
* GitHub issues is opened mainly for development purposes. If you want to ask someone to help solving your problem, go to some community site like [Gitter](https://gitter.im/yyuu/pyenv), [StackOverflow](https://stackoverflow.com/questions/tagged/pyenv), etc.
* [ ] 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.
### Description
### 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:
@ -21,8 +34,12 @@ Make sure you have checked all steps below.
- [ ] 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
<reproduce the problem>
set +x

View file

@ -0,0 +1,24 @@
---
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.

View file

@ -7,31 +7,13 @@ jobs:
matrix:
os:
- ubuntu-22.04
- ubuntu-20.04
- macos-12
- macos-11
- ubuntu-24.04
- macos-14
- macos-15
- macos-15-intel
- macos-26
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
# Normally, we would use the superbly maintained...
# - uses: actions/setup-python@v2
# with:
# python-version: ${{ matrix.python-version }}
# ... but in the repo, we want to test pyenv builds on Ubuntu
# - run: |
# sudo apt-get install -y build-essential libssl-dev zlib1g-dev libbz2-dev \
# libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev \
# xz-utils tk-dev libffi-dev liblzma-dev python-openssl git
# https://github.com/pyenv/pyenv#installation
#- env:
# PYENV_ROOT: /home/runner/work/pyenv/pyenv
# run: |
# echo $PYENV_ROOT
# echo "$PYENV_ROOT/shims:$PYENV_ROOT/bin" >> $GITHUB_PATH
# macos-11 Github Actions env has an old `readlink` and lacks `greadlink` which causes Bats to break
- run: |
if [[ $RUNNER_OS == "macOS" ]] && [[ $(sw_vers -productVersion | awk -F. '{print $1}') -lt 12 ]]; then
brew install coreutils
fi
- run: git clone https://github.com/bats-core/bats-core.git --depth=1 -b v1.2.0 bats
- run: git clone https://github.com/bats-core/bats-core.git --depth=1 -b v1.10.0 bats
- run: bats/bin/bats --tap test

View file

@ -1,62 +1,131 @@
## Version History
#### 1.1.5
## v1.4.0
* Fix POSIX sh (dash) compatibility in pyenv-virtualenv-init by @chrisolof in https://github.com/pyenv/pyenv-virtualenv/pull/526
* Improve performance and output of `pyenv virtualenvs` by @samdoran in https://github.com/pyenv/pyenv-virtualenv/pull/502
## v1.3.0
* CI: cleanup by @native-api in https://github.com/pyenv/pyenv-virtualenv/pull/521
* CI: tests: use Bats 1.10; support concurrent, out-of-order and multiple-times execution of stub commands; fix race condition between concurrent stubs by @native-api in https://github.com/pyenv/pyenv-virtualenv/pull/520
* Drastically speed up precommand hook by caching active version to skip redundant `activate` calls by @jakelodwick in https://github.com/pyenv/pyenv-virtualenv/pull/523
## 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)
#### 1.1.4
## v1.1.4
* Support newer conda (#290)
* Prefer `python3.x` executable if available (#206, #282, #296)
#### 1.1.3
## v1.1.3
* No code changes since 1.1.2
#### 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)
#### 1.1.1
## 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)
#### 1.1.0
## v1.1.0
* fish: use "set -gx" instead of "setenv" (#215, #216, #217, #218)
#### 1.0.0
## v1.0.0
* Use similar versioning scheme as pyenv; YYYYMMDD -> X.Y.Z
#### 20160716
## 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)
#### 20160315
## v20160315
* Evaluate `${PATH}` when outputted code is eval'd. (#154)
* Set proper `CONDA_DEFAULT_ENV` for shorter name (#160)
#### 20160202
## v20160202
* Install virtualenv 13.1.2 for CPython/Stackless 3.2.x (yyuu/pyenv#531)
#### 20160112
## v20160112
* Fix problem with `virtualenv` to look up executables from source version with `--system-site-packages` (#62)
#### 20151229
## v20151229
* Fix `deactivate` error on `fish` (#136)
#### 20151222
## v20151222
* Improved interoperability with Anaconda/Miniconda (#103, #106, #107, #108)
* Create `virtualenv` inside `envs` directory of source version, like Anaconda/Miniconda (#103, #107)
@ -66,49 +135,49 @@
* Add `--skip-aliases` to `pyenv virtualenvs` (#120)
* Stop showing `version not installed` warning messages in precmd (#49)
#### 20151103
## 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)
#### 20151006
## 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)
#### 20150719
## 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)
#### 20150526
## 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)
#### 20150119
## 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)
#### 20141106
## v20141106
* Stop creating after `ensurepip` since it has done by `ensurepip` itself
* Suppress some useless warnings from `pyenv virtualenv-init`
#### 20141012
## 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)
#### 20140705
## v20140705
* Display information on auto-(de)?activation
* Support manual (de)?activation with auto-activation enabled (#32, #34)
@ -116,88 +185,88 @@
* Use https://bootstrap.pypa.io/ to install setuptools and pip
* Create backup of original virtualenv within `$(pyenv root)/versions` when `--upgrade`
#### 20140615
## v20140615
* Fix incompatibility issue of `pyenv activate` and `pyenv deactivate` (#26)
* Workaround for the issue with pyenv-which-ext (#26)
#### 20140614
## v20140614
* Add `pyenv virtualenv-init` to enable auto-activation feature (#24)
* Create symlinks for executables with version suffix (yyuu/pyenv#182)
#### 20140602
## 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)
#### 20140421
## 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)
#### 20140123
## 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
#### 20140110.1
## v20140110.1
* Fix install script
#### 20140110
## v20140110
* Support environment variables of `EZ_SETUP` and `GET_PIP`.
* Support a short option `-p` of `virtualenv`.
#### 20131216
## v20131216
* Use latest release of setuptools and pip if the version not given via environment variables.
#### 20130622
## 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`.
#### 20130614
## v20130614
* Add `pyenv virtualenvs` to list all virtualenv versions.
* *EXPERIMENTAL*: Add `--upgrade` option to re-create virtualenv with migrating packages
#### 20130527
## 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.
#### 20130507
## v20130507
* Display virtualenv information in `--help` and `--version`
* Update virtualenv version; 1.8.4 -> 1.9.1
#### 20130307
## 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
#### 20130218
## v20130218
* Add pyenv 0.2.x (rbenv 0.4.x) style help messages.
#### 20121023
## 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.
#### 20120927
## v20120927
* Initial public release.

View file

@ -1,4 +1,4 @@
Copyright (c) 2015 Yamashita, Yuu
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

15
MAINTENANCE.md Normal file
View file

@ -0,0 +1,15 @@
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

View file

@ -28,21 +28,33 @@ From inside that directory you can:
- 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**
```sh
$ git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv
```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.
```sh
$ echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc
```bash
echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc
```
**Fish shell note**: Add this to your `~/.config/fish/config.fish`
```sh
```fish
status --is-interactive; and pyenv virtualenv-init - | source
```
@ -50,8 +62,8 @@ From inside that directory you can:
3. **Restart your shell to enable pyenv-virtualenv**
```sh
$ exec "$SHELL"
```bash
exec "$SHELL"
```
@ -66,17 +78,17 @@ installed, you will also be able to use the `pyenv virtualenv` command.
with Homebrew.*
```sh
$ brew install pyenv-virtualenv
brew install pyenv-virtualenv
```
Or, if you would like to install the latest development release:
```sh
$ brew install --HEAD pyenv-virtualenv
brew install --HEAD pyenv-virtualenv
```
After installation, you'll still need to do
[Pyenv shell setup steps](https://github.com/pyenv/pyenv#basic-github-checkout)
[Pyenv shell setup steps](https://github.com/pyenv/pyenv#b-set-up-your-shell-environment-for-pyenv)
then add
```sh
eval "$(pyenv virtualenv-init -)"
@ -93,7 +105,7 @@ To create a virtualenv for the Python version used with pyenv, run
of the virtualenv directory. For example,
```sh
$ pyenv virtualenv 2.7.10 my-virtual-env-2.7.10
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
@ -237,6 +249,7 @@ You can set certain environment variables to control pyenv-virtualenv.
* `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

View file

@ -22,10 +22,8 @@ fi
{ printf "\x1B[31;1m"
echo
echo "Failed to activate virtualenv."
echo
echo "Perhaps pyenv-virtualenv has not been loaded into your shell properly."
echo "Please restart current shell and try again."
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

View file

@ -11,10 +11,8 @@ set -e
{ printf "\x1B[31;1m"
echo
echo "Failed to deactivate virtualenv."
echo
echo "Perhaps pyenv-virtualenv has not been loaded into your shell properly."
echo "Please restart current shell and try again."
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

View file

@ -25,6 +25,27 @@ resolve_link() {
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" )
@ -75,8 +96,8 @@ fi
venv="${versions}"
if [ -n "${VIRTUAL_ENV}" ]; then
# exit as success if some virtualenv is already activated outside from pyenv-virtualenv
if [ -z "${PYENV_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
@ -137,6 +158,9 @@ 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
@ -221,16 +245,31 @@ if [ -z "${PYENV_VIRTUALENV_DISABLE_PROMPT}" ]; then
case "${shell}" in
fish )
if [ -z "${QUIET}" ]; then
echo "pyenv-virtualenv: prompt changing not working for fish." 1>&2
cat <<EOS
functions -e _pyenv_old_prompt # remove old prompt function if exists.
# since everything is in memory, it's safe to
# remove it.
functions -c fish_prompt _pyenv_old_prompt # backup old prompt function
# from python-venv
function fish_prompt
set -l prompt (_pyenv_old_prompt) # call old prompt function first since it might
# read exit status
echo -n "(${venv}) " # add virtualenv to prompt
string join -- \n \$prompt # handle multiline prompts
end
EOS
fi
;;
* )
if [ -z "${QUIET}" ]; then
echo "pyenv-virtualenv: prompt changing will be removed from future release. configure \`export PYENV_VIRTUALENV_DISABLE_PROMPT=1' to simulate the behavior." 1>&2
if [ -z "${PYENV_VIRTUALENV_PROMPT}" ]; then
PYENV_VIRTUALENV_PROMPT="(${venv})"
else
PYENV_VIRTUALENV_PROMPT="${PYENV_VIRTUALENV_PROMPT/\{venv\}/${venv}}"
fi
cat <<EOS
export _OLD_VIRTUAL_PS1="\${PS1:-}";
export PS1="(${venv}) \${PS1:-}";
export PS1="${PYENV_VIRTUALENV_PROMPT} \${PS1:-}";
EOS
;;
esac
@ -261,3 +300,6 @@ if [ -d "${prefix}/conda-meta" ] ||
esac
shopt -u nullglob
fi
# Execute `after_activate` hooks.
for hook in "${after_hooks[@]}"; do eval "$hook"; done

View file

@ -16,6 +16,27 @@ fi
unset FORCE
unset QUIET
# Define `before_deactivate` and `after_deactivate` functions that allow
# plugin hooks to register a string of code for execution before or
# after deactivating a virtualenv.
declare -a before_hooks after_hooks
before_deactivate() {
local hook="$1"
before_hooks["${#before_hooks[@]}"]="$hook"
}
after_deactivate() {
local hook="$1"
after_hooks["${#after_hooks[@]}"]="$hook"
}
# Load plugin hooks.
OLDIFS="$IFS"
IFS=$'\n' scripts=(`pyenv-hooks deactivate`)
IFS="$OLDIFS"
for script in "${scripts[@]}"; do source "$script"; done
while [ $# -gt 0 ]; do
case "$1" in
"-f" | "--force" )
@ -54,6 +75,9 @@ 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
@ -163,7 +187,15 @@ esac
case "${shell}" in
fish )
:
cat <<EOS
# check if old prompt function exists
if functions -q _pyenv_old_prompt
# remove old prompt function if exists.
functions -e fish_prompt
functions -c _pyenv_old_prompt fish_prompt
functions -e _pyenv_old_prompt
end
EOS
;;
* )
cat <<EOS
@ -191,3 +223,6 @@ fi;
EOS
;;
esac
# Execute `after_deactivate` hooks.
for hook in "${after_hooks[@]}"; do eval "$hook"; done

View file

@ -13,7 +13,7 @@
# -u/--upgrade Imply --force
#
PYENV_VIRTUALENV_VERSION="1.1.5"
PYENV_VIRTUALENV_VERSION="1.4.0"
set -e
[ -n "$PYENV_DEBUG" ] && set -x
@ -24,7 +24,7 @@ fi
# Provide pyenv completions
if [ "$1" = "--complete" ]; then
exec pyenv-versions --bare
exec pyenv-versions --bare --skip-envs
fi
unset PIP_REQUIRE_VENV
@ -54,6 +54,12 @@ parse_options() {
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"
}
@ -149,9 +155,17 @@ detect_venv() {
if [ -x "${prefix}/bin/virtualenv" ]; then
HAS_VIRTUALENV=1
fi
# Prefer `python3.x` executable if available (#206, #282)
local python
for python in "python${PYENV_VERSION%.*}" "python${PYENV_VERSION%%.*}" "python"; do
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}"
@ -311,7 +325,7 @@ else
fi
if [[ -n "${VERSION_NAME}" ]] && command -v pyenv-latest >/dev/null; then
VERSION_NAME="$(pyenv-latest -q "${VERSION_NAME}" || echo "${VERSION_NAME}")"
VERSION_NAME="$(pyenv-latest -f "${VERSION_NAME}")"
fi
if [ -z "${VERSION_NAME}" ] || [ -z "${VIRTUALENV_NAME}" ]; then
@ -336,10 +350,20 @@ 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
echo "pyenv-virtualenv: \`${PYENV_VERSION}' is not installed in pyenv." 1>&2
not_installed_message "${PYENV_VERSION}"
exit 1
fi
@ -441,7 +465,8 @@ else
if [ -x "${python}" ]; then
VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="--python=${python}"
else
echo "pyenv-virtualenv: \`${VIRTUALENV_PYTHON##*/}' is not installed in pyenv." 1>&2
# echo "pyenv-virtualenv: \`${VIRTUALENV_PYTHON##*/}' is not installed in pyenv." 1>&2
not_installed_message "${VIRTUALENV_PYTHON##*/}"
exit 1
fi
fi
@ -580,7 +605,13 @@ STATUS=0
mkdir -p "${PYENV_VIRTUALENV_CACHE_PATH}"
cd "${PYENV_VIRTUALENV_CACHE_PATH}"
if [ -n "${USE_CONDA}" ]; then
pyenv-exec conda create $QUIET $VERBOSE --name "${VIRTUALENV_PATH##*/}" --yes "${VIRTUALENV_OPTIONS[@]}" python || STATUS="$?"
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="$?"
@ -589,9 +620,19 @@ else
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
ln -fs "${VIRTUALENV_PATH}" "${COMPAT_VIRTUALENV_PATH}"
# 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

View file

@ -55,26 +55,28 @@ case "$DEFINITION" in
esac
VERSION_NAME="${DEFINITION##*/}"
COMPAT_PREFIX="${PYENV_ROOT}/versions/${VERSION_NAME}"
# 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
PREFIX="${PYENV_ROOT}/versions/${DEFINITION}"
if [ -L "${COMPAT_PREFIX}" ]; then
if [[ "${PREFIX}" != "$(resolve_link "${COMPAT_PREFIX}" 2>/dev/null || true)" ]]; then
unset COMPAT_PREFIX
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 "${COMPAT_PREFIX}" ]; then
PREFIX="$(resolve_link "${COMPAT_PREFIX}" 2>/dev/null || true)"
if [[ "${PREFIX%/*/envs/*}" != "${PYENV_ROOT}/versions" ]]; then
echo "pyenv-virtualenv: \`${COMPAT_PREFIX}' is a symlink for unknown location." 1>&2
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
PREFIX="${PYENV_ROOT}/versions/${VERSION_NAME}"
unset COMPAT_PREFIX
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
@ -82,23 +84,25 @@ else
fi
fi
if [ -z "$FORCE" ]; then
if [ ! -d "$PREFIX" ]; then
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
read -p "pyenv-virtualenv: remove $PREFIX? (y/N) "
if [ -z "$FORCE" ]; then
read -p "pyenv-virtualenv: remove $ENV_PREFIX? (y/N) "
case "$REPLY" in
y* | Y* ) ;;
* ) exit 1 ;;
esac
fi
if [ -d "$PREFIX" ]; then
rm -rf "$PREFIX"
if [ -L "$COMPAT_PREFIX" ]; then
rm -rf "$COMPAT_PREFIX"
fi
pyenv-rehash
rm -rf "$ENV_PREFIX"
if [ -L "$ENV_COMPAT_PREFIX" ]; then
rm -rf "$ENV_COMPAT_PREFIX"
fi
pyenv-rehash

View file

@ -9,6 +9,23 @@
set -e
[ -n "$PYENV_DEBUG" ] && set -x
# Detect stat format for mtime: GNU uses -c %Y, BSD uses -f %m
# -L follows symlinks: a symlinked .python-version reflects target changes
if stat -L -c %Y / >/dev/null 2>&1; then
_stat_fmt="-L -c %Y"
else
_stat_fmt="-L -f %m"
fi
# Check for version-name hooks at init time. Hooks can alter version
# resolution in ways the mtime cache cannot track. If present, the hook
# falls back to upstream behavior (no caching). Restart shell after
# installing or removing pyenv plugins.
_has_version_hooks=""
if [ -n "$(pyenv hooks version-name 2>/dev/null)" ]; then
_has_version_hooks=1
fi
resolve_link() {
$(type -p greadlink readlink | head -1) "$1"
}
@ -106,57 +123,147 @@ fish )
cat <<EOS
function _pyenv_virtualenv_hook --on-event fish_prompt;
set -l ret \$status
EOS
if [ -z "$_has_version_hooks" ]; then
cat <<EOS
if test "\$PYENV_VERSION" = "\$_PYENV_VH_VERSION" \\
-a "\$VIRTUAL_ENV" = "\$_PYENV_VH_VENV"
if test -n "\$PYENV_VERSION"
return \$ret
end
if test "\$PWD" = "\$_PYENV_VH_PWD" \\
-a "(stat ${_stat_fmt} \$_PYENV_VH_PATHS 2>/dev/null)" = "\$_PYENV_VH_MTIMES"
return \$ret
end
end
EOS
fi
cat <<EOS
if [ -n "\$VIRTUAL_ENV" ]
pyenv activate --quiet; or pyenv deactivate --quiet; or true
else
pyenv activate --quiet; or true
end
EOS
if [ -z "$_has_version_hooks" ]; then
cat <<EOS
set -g _PYENV_VH_PWD "\$PWD"
set -g _PYENV_VH_VERSION "\$PYENV_VERSION"
set -g _PYENV_VH_VENV "\$VIRTUAL_ENV"
set -l d "\$PWD"
set -l _pvh_found_local 0
set -g _PYENV_VH_PATHS
while true
if test -f "\$d/.python-version"; or test -L "\$d/.python-version"
set -g _PYENV_VH_PATHS \$_PYENV_VH_PATHS "\$d/.python-version"
if test -f "\$d/.python-version"
set _pvh_found_local 1
break
end
else
set -g _PYENV_VH_PATHS \$_PYENV_VH_PATHS "\$d"
end
test "\$d" = "/"; and break
set d (string replace -r '/[^/]*\$' '' -- "\$d")
test -z "\$d"; and set d "/"
end
if test "\$_pvh_found_local" = "0"
set -g _PYENV_VH_PATHS \$_PYENV_VH_PATHS "\$PYENV_ROOT/version"
end
set -g _PYENV_VH_MTIMES (stat ${_stat_fmt} \$_PYENV_VH_PATHS 2>/dev/null)
EOS
fi
cat <<EOS
return \$ret
end
EOS
;;
ksh )
cat <<EOS
function _pyenv_virtualenv_hook() {
EOS
;;
* )
bash|zsh )
cat <<EOS
_pyenv_virtualenv_hook() {
EOS
;;
esac
if [[ "$shell" != "fish" ]]; then
cat <<EOS
local ret=\$?
EOS
if [ -z "$_has_version_hooks" ]; then
cat <<EOS
if [ "\${PYENV_VERSION-}" = "\${_PYENV_VH_VERSION-}" ] \\
&& [ "\${VIRTUAL_ENV-}" = "\${_PYENV_VH_VENV-}" ]; then
if [ -n "\${PYENV_VERSION-}" ]; then
return \$ret
fi
if [ "\${PWD}" = "\${_PYENV_VH_PWD-}" ] \\
&& [ "\$(stat ${_stat_fmt} "\${_PYENV_VH_PATHS[@]}" 2>/dev/null)" = "\${_PYENV_VH_MTIMES-}" ]; then
return \$ret
fi
fi
EOS
fi
cat <<EOS
if [ -n "\${VIRTUAL_ENV-}" ]; then
eval "\$(pyenv sh-activate --quiet || pyenv sh-deactivate --quiet || true)" || true
else
eval "\$(pyenv sh-activate --quiet || true)" || true
fi
EOS
if [ -z "$_has_version_hooks" ]; then
cat <<EOS
_PYENV_VH_PWD="\${PWD}"
_PYENV_VH_VERSION="\${PYENV_VERSION-}"
_PYENV_VH_VENV="\${VIRTUAL_ENV-}"
local _pvh_d="\${PWD}" _pvh_found_local=0
_PYENV_VH_PATHS=()
while :; do
if [ -f "\${_pvh_d}/.python-version" ] || [ -L "\${_pvh_d}/.python-version" ]; then
_PYENV_VH_PATHS+=("\${_pvh_d}/.python-version")
if [ -f "\${_pvh_d}/.python-version" ]; then
_pvh_found_local=1
break
fi
else
_PYENV_VH_PATHS+=("\${_pvh_d}")
fi
[ "\${_pvh_d}" = "/" ] && break
_pvh_d="\${_pvh_d%/*}"
[ -z "\${_pvh_d}" ] && _pvh_d="/"
done
if [ "\${_pvh_found_local}" = "0" ]; then
_PYENV_VH_PATHS+=("\${PYENV_ROOT}/version")
fi
_PYENV_VH_MTIMES="\$(stat ${_stat_fmt} "\${_PYENV_VH_PATHS[@]}" 2>/dev/null)"
EOS
fi
cat <<EOS
return \$ret
};
EOS
;;
esac
case "$shell" in
bash )
cat <<EOS
case "$shell" in
bash )
cat <<EOS
if ! [[ "\${PROMPT_COMMAND-}" =~ _pyenv_virtualenv_hook ]]; then
PROMPT_COMMAND="_pyenv_virtualenv_hook;\${PROMPT_COMMAND-}"
fi
EOS
;;
zsh )
cat <<EOS
;;
zsh )
cat <<EOS
typeset -g -a precmd_functions
if [[ -z \$precmd_functions[(r)_pyenv_virtualenv_hook] ]]; then
precmd_functions=(_pyenv_virtualenv_hook \$precmd_functions);
fi
EOS
;;
* )
# FIXME: what should i do here??
;;
esac
fi
;;
* )
# No prompt command support or it's installed elsewhere
;;
esac

View file

@ -26,13 +26,17 @@ if [ -z "$PYENV_ROOT" ]; then
PYENV_ROOT="${HOME}/.pyenv"
fi
OLDIFS="$IFS"
IFS=:
if [ -n "$1" ]; then
versions=($@)
IFS=: PYENV_VERSION="${versions[*]}"
# $@ is not affected by IFS
versions=("$@")
PYENV_VERSION="${versions[*]}"
export PYENV_VERSION
else
IFS=: versions=($(pyenv-version-name))
versions=($(pyenv-version-name))
fi
IFS="$OLDIFS"
append_virtualenv_prefix() {
if [ -d "${VIRTUALENV_PREFIX_PATH}" ]; then
@ -49,7 +53,18 @@ for version in "${versions[@]}"; do
echo "pyenv-virtualenv: version \`${version}' is not a virtualenv" 1>&2
exit 1
fi
PYENV_PREFIX_PATH="$(pyenv-prefix "${version}")"
# In the vast majority of cases, there's a direct match and
# not spawning `pyenv-prefix' saves about half the invocation time
# with a signle argument which accumulates when called repeatedly
# (e.g. from `pyenv-virtualenvs').
# `pyenv-prefix' also does not have hooks to worry about.
# XXX: refactor the test into a shared module?
PYENV_PREFIX_PATH="${PYENV_ROOT}/versions/${version}"
if [[ ! -d "$PYENV_PREFIX_PATH" ]]; then
PYENV_PREFIX_PATH="$(pyenv-prefix "${version}")"
fi
if [ -x "${PYENV_PREFIX_PATH}/bin/python" ]; then
if [ -f "${PYENV_PREFIX_PATH}/bin/activate" ]; then
if [ -f "${PYENV_PREFIX_PATH}/bin/conda" ]; then
@ -94,4 +109,7 @@ for version in "${versions[@]}"; do
fi
done
IFS=: echo "${VIRTUALENV_PREFIX_PATHS[*]}"
OLDIFS="$IFS"
IFS=:
echo "${VIRTUALENV_PREFIX_PATHS[*]}"
IFS="$OLDIFS"

View file

@ -6,24 +6,9 @@
# 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
[[ -n $PYENV_DEBUG ]] && set -x
. ${script_path%/*}/../libexec/pyenv-virtualenv-realpath
if [ -z "$PYENV_ROOT" ]; then
if [[ -z $PYENV_ROOT ]]; then
PYENV_ROOT="${HOME}/.pyenv"
fi
@ -47,28 +32,26 @@ 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=""
if [[ ${BASH_VERSINFO[0]} -gt 3 ]]; then
declare -A current_versions
else
current_versions=()
fi
if [[ -z $bare ]]; then
hit_prefix="* "
miss_prefix=" "
OLDIFS="$IFS"
IFS=: current_versions=($(pyenv-version-name || true))
IFS=:
if [[ ${BASH_VERSINFO[0]} -gt 3 ]]; then
for i in $(pyenv-version-name || true); do
current_versions["$i"]="1"
done
else
read -r -a current_versions <<< "$(pyenv-version-name || true)"
fi
IFS="$OLDIFS"
print_origin="1"
include_system=""
fi
num_versions=0
exists() {
local car="$1"
local cdar
@ -82,39 +65,67 @@ exists() {
}
print_version() {
if exists "$1" "${current_versions[@]}"; then
echo "${hit_prefix}${1}${print_origin+$2}"
else
echo "${miss_prefix}${1}${print_origin+$2}"
local version="${1:?}"
if [[ -n $bare ]]; then
echo "$version"
return
fi
local path="${2:?}"
if [[ -L "$path" ]]; then
version_repr="$version --> $(readlink "$path")"
else
version_repr="$version (created from $(pyenv-virtualenv-prefix "$version" 2>/dev/null))"
fi
if [[ ${BASH_VERSINFO[0]} -gt 3 && ${current_versions["$1"]} ]] || \
{ [[ ${BASH_VERSINFO[0]} -le 3 ]] && exists "$1" "${current_versions[@]}"; }; then
echo "${hit_prefix}${version_repr} (set by $(pyenv-version-origin))"
else
echo "${miss_prefix}${version_repr}"
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
version_dir_entries=("$versions_dir"/*)
venv_dir_entries=("$versions_dir"/*/envs/*)
if sort --version-sort </dev/null >/dev/null 2>&1; then
# system sort supports version sorting
OLDIFS="$IFS"
IFS='||'
read -r -a version_dir_entries <<< "$(
printf "%s||" "${version_dir_entries[@]}" |
sort --version-sort
)"
read -r -a venv_dir_entries <<< "$(
printf "%s||" "${venv_dir_entries[@]}" |
sort --version-sort
)"
IFS="$OLDIFS"
fi
for env_path in "${venv_dir_entries[@]}"; do
if [[ -d ${env_path} ]]; then
print_version "${env_path#"${PYENV_ROOT}"/versions/}" "${env_path}"
fi
done
for env_path in "${version_dir_entries[@]}"; do
if [[ -d ${env_path} ]]; then
if [[ -L ${env_path} ]]; then
if [[ -z $skip_aliases ]]; then
print_version "${env_path#"${PYENV_ROOT}"/versions/}" "${env_path}"
fi
# Mimics the test from pyenv-virtualenv-prefix
# XXX: refactor itto a shared module ?
elif [[ -f "${env_path}/bin/activate" ]]; then
print_version "${env_path#"${PYENV_ROOT}"/versions/}" "${env_path}"
fi
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

View file

@ -15,7 +15,9 @@ setup() {
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" {
@ -33,7 +35,6 @@ setup() {
deactivated
export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv";
export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv";
pyenv-virtualenv: prompt changing will be removed from future release. configure \`export PYENV_VIRTUALENV_DISABLE_PROMPT=1' to simulate the behavior.
export _OLD_VIRTUAL_PS1="\${PS1:-}";
export PS1="(venv) \${PS1:-}";
EOS
@ -44,6 +45,31 @@ EOS
unstub pyenv-sh-deactivate
}
@test "activate virtualenv from current version with custom prompt" {
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" PYENV_VIRTUALENV_PROMPT='venv:{venv}' run pyenv-sh-activate
assert_success
assert_output <<EOS
deactivated
export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv";
export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv";
export _OLD_VIRTUAL_PS1="\${PS1:-}";
export PS1="venv:venv \${PS1:-}";
EOS
unstub pyenv-version-name
unstub pyenv-virtualenv-prefix
unstub pyenv-prefix
unstub pyenv-sh-deactivate
}
@test "activate virtualenv from current version (quiet)" {
export PYENV_VIRTUALENV_INIT=1
@ -86,7 +112,6 @@ deactivated
pyenv-virtualenv: activate venv
export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv";
export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv";
pyenv-virtualenv: prompt changing will be removed from future release. configure \`export PYENV_VIRTUALENV_DISABLE_PROMPT=1' to simulate the behavior.
export _OLD_VIRTUAL_PS1="\${PS1:-}";
export PS1="(venv) \${PS1:-}";
EOS
@ -114,7 +139,6 @@ export PYENV_VERSION="venv";
export PYENV_ACTIVATE_SHELL=1;
export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv";
export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv";
pyenv-virtualenv: prompt changing will be removed from future release. configure \`export PYENV_VIRTUALENV_DISABLE_PROMPT=1' to simulate the behavior.
export _OLD_VIRTUAL_PS1="\${PS1:-}";
export PS1="(venv) \${PS1:-}";
EOS
@ -140,7 +164,18 @@ EOS
deactivated
set -gx PYENV_VIRTUAL_ENV "${PYENV_ROOT}/versions/venv";
set -gx VIRTUAL_ENV "${PYENV_ROOT}/versions/venv";
pyenv-virtualenv: prompt changing not working for fish.
functions -e _pyenv_old_prompt # remove old prompt function if exists.
# since everything is in memory, it's safe to
# remove it.
functions -c fish_prompt _pyenv_old_prompt # backup old prompt function
# from python-venv
function fish_prompt
set -l prompt (_pyenv_old_prompt) # call old prompt function first since it might
# read exit status
echo -n "(venv) " # add virtualenv to prompt
string join -- \n \$prompt # handle multiline prompts
end
EOS
unstub pyenv-version-name
@ -166,7 +201,18 @@ set -gx PYENV_VERSION "venv";
set -gx PYENV_ACTIVATE_SHELL 1;
set -gx PYENV_VIRTUAL_ENV "${PYENV_ROOT}/versions/venv";
set -gx VIRTUAL_ENV "${PYENV_ROOT}/versions/venv";
pyenv-virtualenv: prompt changing not working for fish.
functions -e _pyenv_old_prompt # remove old prompt function if exists.
# since everything is in memory, it's safe to
# remove it.
functions -c fish_prompt _pyenv_old_prompt # backup old prompt function
# from python-venv
function fish_prompt
set -l prompt (_pyenv_old_prompt) # call old prompt function first since it might
# read exit status
echo -n "(venv) " # add virtualenv to prompt
string join -- \n \$prompt # handle multiline prompts
end
EOS
unstub pyenv-version-name
@ -191,7 +237,6 @@ export PYENV_VERSION="venv27";
export PYENV_ACTIVATE_SHELL=1;
export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv27";
export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv27";
pyenv-virtualenv: prompt changing will be removed from future release. configure \`export PYENV_VIRTUALENV_DISABLE_PROMPT=1' to simulate the behavior.
export _OLD_VIRTUAL_PS1="\${PS1:-}";
export PS1="(venv27) \${PS1:-}";
EOS
@ -217,7 +262,6 @@ export PYENV_VERSION="venv27";
export PYENV_ACTIVATE_SHELL=1;
export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv27";
export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv27";
pyenv-virtualenv: prompt changing will be removed from future release. configure \`export PYENV_VIRTUALENV_DISABLE_PROMPT=1' to simulate the behavior.
export _OLD_VIRTUAL_PS1="\${PS1:-}";
export PS1="(venv27) \${PS1:-}";
EOS
@ -243,7 +287,18 @@ set -gx PYENV_VERSION "venv27";
set -gx PYENV_ACTIVATE_SHELL 1;
set -gx PYENV_VIRTUAL_ENV "${PYENV_ROOT}/versions/venv27";
set -gx VIRTUAL_ENV "${PYENV_ROOT}/versions/venv27";
pyenv-virtualenv: prompt changing not working for fish.
functions -e _pyenv_old_prompt # remove old prompt function if exists.
# since everything is in memory, it's safe to
# remove it.
functions -c fish_prompt _pyenv_old_prompt # backup old prompt function
# from python-venv
function fish_prompt
set -l prompt (_pyenv_old_prompt) # call old prompt function first since it might
# read exit status
echo -n "(venv27) " # add virtualenv to prompt
string join -- \n \$prompt # handle multiline prompts
end
EOS
unstub pyenv-virtualenv-prefix
@ -267,7 +322,18 @@ set -gx PYENV_VERSION "venv27";
set -gx PYENV_ACTIVATE_SHELL 1;
set -gx PYENV_VIRTUAL_ENV "${PYENV_ROOT}/versions/venv27";
set -gx VIRTUAL_ENV "${PYENV_ROOT}/versions/venv27";
pyenv-virtualenv: prompt changing not working for fish.
functions -e _pyenv_old_prompt # remove old prompt function if exists.
# since everything is in memory, it's safe to
# remove it.
functions -c fish_prompt _pyenv_old_prompt # backup old prompt function
# from python-venv
function fish_prompt
set -l prompt (_pyenv_old_prompt) # call old prompt function first since it might
# read exit status
echo -n "(venv27) " # add virtualenv to prompt
string join -- \n \$prompt # handle multiline prompts
end
EOS
unstub pyenv-virtualenv-prefix
@ -390,7 +456,6 @@ export PYENV_VERSION="venv27:2.7.10";
export PYENV_ACTIVATE_SHELL=1;
export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv27";
export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv27";
pyenv-virtualenv: prompt changing will be removed from future release. configure \`export PYENV_VIRTUALENV_DISABLE_PROMPT=1' to simulate the behavior.
export _OLD_VIRTUAL_PS1="\${PS1:-}";
export PS1="(venv27) \${PS1:-}";
EOS
@ -400,6 +465,34 @@ EOS
unstub pyenv-prefix
}
@test "do nothing if a 3rd-party virtualenv is active" {
export PYENV_VIRTUALENV_INIT=1
export VIRTUAL_ENV="${TMP}/venv-3rd-party"
unset PYENV_VIRTUAL_ENV
PYENV_SHELL="bash" run pyenv-sh-activate "venv"
assert_success
assert_output <<EOS
pyenv-virtualenv: virtualenv \`${TMP}/venv-3rd-party' is already activated
true
EOS
}
@test "do nothing if a 3rd-party virtualenv is active over ours" {
export PYENV_VIRTUALENV_INIT=1
export VIRTUAL_ENV="${TMP}/venv-3rd-party"
export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv"
PYENV_SHELL="bash" run pyenv-sh-activate "venv"
assert_success
assert_output <<EOS
pyenv-virtualenv: virtualenv \`${TMP}/venv-3rd-party' is already activated
true
EOS
}
@test "should fail if activate is invoked as a command" {
run pyenv-activate

View file

@ -16,7 +16,13 @@ setup() {
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"
}
teardown() {
unstub pyenv-hooks
}
@test "activate conda root from current version" {
@ -36,7 +42,6 @@ deactivated
export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/anaconda-2.3.0";
export VIRTUAL_ENV="${PYENV_ROOT}/versions/anaconda-2.3.0";
export CONDA_DEFAULT_ENV="root";
pyenv-virtualenv: prompt changing will be removed from future release. configure \`export PYENV_VIRTUALENV_DISABLE_PROMPT=1' to simulate the behavior.
export _OLD_VIRTUAL_PS1="\${PS1:-}";
export PS1="(anaconda-2.3.0) \${PS1:-}";
export CONDA_PREFIX="${TMP}/pyenv/versions/anaconda-2.3.0";
@ -49,6 +54,35 @@ EOS
teardown_conda "anaconda-2.3.0"
}
@test "activate conda root from current version with custom prompt" {
export PYENV_VIRTUALENV_INIT=1
setup_conda "anaconda-2.3.0"
stub pyenv-version-name "echo anaconda-2.3.0"
stub pyenv-virtualenv-prefix "anaconda-2.3.0 : echo \"${PYENV_ROOT}/versions/anaconda-2.3.0\""
stub pyenv-prefix "anaconda-2.3.0 : echo \"${PYENV_ROOT}/versions/anaconda-2.3.0\""
stub pyenv-sh-deactivate "--force --quiet : echo deactivated"
PYENV_SHELL="bash" PYENV_VERSION="anaconda-2.3.0" PYENV_VIRTUALENV_PROMPT='venv:{venv}' run pyenv-sh-activate
assert_success
assert_output <<EOS
deactivated
export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/anaconda-2.3.0";
export VIRTUAL_ENV="${PYENV_ROOT}/versions/anaconda-2.3.0";
export CONDA_DEFAULT_ENV="root";
export _OLD_VIRTUAL_PS1="\${PS1:-}";
export PS1="venv:anaconda-2.3.0 \${PS1:-}";
export CONDA_PREFIX="${TMP}/pyenv/versions/anaconda-2.3.0";
EOS
unstub pyenv-version-name
unstub pyenv-virtualenv-prefix
unstub pyenv-prefix
unstub pyenv-sh-deactivate
teardown_conda "anaconda-2.3.0"
}
@test "activate conda root from current version (fish)" {
export PYENV_VIRTUALENV_INIT=1
@ -66,7 +100,18 @@ deactivated
set -gx PYENV_VIRTUAL_ENV "${TMP}/pyenv/versions/anaconda-2.3.0";
set -gx VIRTUAL_ENV "${TMP}/pyenv/versions/anaconda-2.3.0";
set -gx CONDA_DEFAULT_ENV "root";
pyenv-virtualenv: prompt changing not working for fish.
functions -e _pyenv_old_prompt # remove old prompt function if exists.
# since everything is in memory, it's safe to
# remove it.
functions -c fish_prompt _pyenv_old_prompt # backup old prompt function
# from python-venv
function fish_prompt
set -l prompt (_pyenv_old_prompt) # call old prompt function first since it might
# read exit status
echo -n "(anaconda-2.3.0) " # add virtualenv to prompt
string join -- \n \$prompt # handle multiline prompts
end
EOS
unstub pyenv-version-name
@ -95,7 +140,6 @@ export PYENV_ACTIVATE_SHELL=1;
export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/miniconda-3.9.1";
export VIRTUAL_ENV="${PYENV_ROOT}/versions/miniconda-3.9.1";
export CONDA_DEFAULT_ENV="root";
pyenv-virtualenv: prompt changing will be removed from future release. configure \`export PYENV_VIRTUALENV_DISABLE_PROMPT=1' to simulate the behavior.
export _OLD_VIRTUAL_PS1="\${PS1:-}";
export PS1="(miniconda-3.9.1) \${PS1:-}";
export CONDA_PREFIX="${TMP}/pyenv/versions/miniconda-3.9.1";
@ -125,7 +169,6 @@ deactivated
export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/anaconda-2.3.0/envs/foo";
export VIRTUAL_ENV="${PYENV_ROOT}/versions/anaconda-2.3.0/envs/foo";
export CONDA_DEFAULT_ENV="foo";
pyenv-virtualenv: prompt changing will be removed from future release. configure \`export PYENV_VIRTUALENV_DISABLE_PROMPT=1' to simulate the behavior.
export _OLD_VIRTUAL_PS1="\${PS1:-}";
export PS1="(anaconda-2.3.0/envs/foo) \${PS1:-}";
export CONDA_PREFIX="${TMP}/pyenv/versions/anaconda-2.3.0/envs/foo";
@ -158,7 +201,6 @@ export PYENV_ACTIVATE_SHELL=1;
export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/miniconda-3.9.1/envs/bar";
export VIRTUAL_ENV="${PYENV_ROOT}/versions/miniconda-3.9.1/envs/bar";
export CONDA_DEFAULT_ENV="bar";
pyenv-virtualenv: prompt changing will be removed from future release. configure \`export PYENV_VIRTUALENV_DISABLE_PROMPT=1' to simulate the behavior.
export _OLD_VIRTUAL_PS1="\${PS1:-}";
export PS1="(miniconda-3.9.1/envs/bar) \${PS1:-}";
export CONDA_PREFIX="${TMP}/pyenv/versions/miniconda-3.9.1/envs/bar";

View file

@ -16,6 +16,11 @@ setup() {
unset PYENV_VIRTUAL_ENV_DISABLE_PROMPT
unset VIRTUAL_ENV_DISABLE_PROMPT
unset _OLD_VIRTUAL_PS1
stub pyenv-hooks "deactivate : echo"
}
teardown() {
unstub pyenv-hooks
}
@test "deactivate conda root" {
@ -77,6 +82,13 @@ if [ -n "\$_OLD_VIRTUAL_PYTHONHOME" ];
set -gx PYTHONHOME "\$_OLD_VIRTUAL_PYTHONHOME";
set -e _OLD_VIRTUAL_PYTHONHOME;
end;
# check if old prompt function exists
if functions -q _pyenv_old_prompt
# remove old prompt function if exists.
functions -e fish_prompt
functions -c _pyenv_old_prompt fish_prompt
functions -e _pyenv_old_prompt
end
if functions -q deactivate;
functions -e deactivate;
end;

View file

@ -9,7 +9,6 @@ setup() {
@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
@ -19,14 +18,12 @@ ${PYENV_ROOT}/versions/anaconda-2.3.0
OUT
unstub pyenv-version-name
unstub pyenv-prefix
teardown_conda "anaconda-2.3.0"
}
@test "display conda env" {
setup_conda "anaconda-2.3.0" "foo"
stub pyenv-version-name "echo anaconda-2.3.0/envs/foo"
stub pyenv-prefix "anaconda-2.3.0/envs/foo : echo \"${PYENV_ROOT}/versions/anaconda-2.3.0/envs/foo\""
PYENV_VERSION="anaconda-2.3.0/envs/foo" run pyenv-virtualenv-prefix
@ -36,6 +33,5 @@ ${PYENV_ROOT}/versions/anaconda-2.3.0/envs/foo
OUT
unstub pyenv-version-name
unstub pyenv-prefix
teardown_conda "anaconda-2.3.0" "foo"
}

View file

@ -26,14 +26,15 @@ unstub_pyenv() {
stub_pyenv "${PYENV_VERSION}"
stub pyenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'"
stub pyenv-virtualenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'"
stub pyenv-exec "conda * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub -N pyenv-exec "conda list * : true"
stub -N pyenv-exec "conda create * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "python -s -m ensurepip : true"
run pyenv-virtualenv venv
assert_success
assert_output <<OUT
PYENV_VERSION=miniconda3-3.16.0 conda create --name venv --yes python
assert_output_wildcards <<OUT
PYENV_VERSION=miniconda3-3.16.0 conda create --name venv --yes --file /dev/fd/*
rehashed
OUT
@ -49,14 +50,14 @@ OUT
stub_pyenv "${PYENV_VERSION}"
stub pyenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'"
stub pyenv-virtualenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'"
stub pyenv-exec "conda * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "conda create * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "python -s -m ensurepip : true"
run pyenv-virtualenv -p python3.5 venv
assert_success
assert_output <<OUT
PYENV_VERSION=miniconda3-3.16.0 conda create --name venv --yes python=3.5 python
PYENV_VERSION=miniconda3-3.16.0 conda create --name venv --yes python=3.5
rehashed
OUT
@ -72,14 +73,14 @@ OUT
stub_pyenv "${PYENV_VERSION}"
stub pyenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'"
stub pyenv-virtualenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'"
stub pyenv-exec "conda * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "conda create * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "python -s -m ensurepip : true"
run pyenv-virtualenv --python=python3.5 venv
assert_success
assert_output <<OUT
PYENV_VERSION=miniconda3-3.16.0 conda create --name venv --yes python=3.5 python
PYENV_VERSION=miniconda3-3.16.0 conda create --name venv --yes python=3.5
rehashed
OUT

View file

@ -1,4 +1,4 @@
#!/usr/bin/env bats
#!/usr/bin/env bats
load test_helper
@ -16,6 +16,7 @@ setup() {
unset PYENV_VIRTUAL_ENV_DISABLE_PROMPT
unset VIRTUAL_ENV_DISABLE_PROMPT
unset _OLD_VIRTUAL_PS1
stub pyenv-hooks "deactivate : echo"
}
@test "deactivate virtualenv" {
@ -224,6 +225,13 @@ if [ -n "\$_OLD_VIRTUAL_PYTHONHOME" ];
set -gx PYTHONHOME "\$_OLD_VIRTUAL_PYTHONHOME";
set -e _OLD_VIRTUAL_PYTHONHOME;
end;
# check if old prompt function exists
if functions -q _pyenv_old_prompt
# remove old prompt function if exists.
functions -e fish_prompt
functions -c _pyenv_old_prompt fish_prompt
functions -e _pyenv_old_prompt
end
if functions -q deactivate;
functions -e deactivate;
end;
@ -250,6 +258,13 @@ if [ -n "\$_OLD_VIRTUAL_PYTHONHOME" ];
set -gx PYTHONHOME "\$_OLD_VIRTUAL_PYTHONHOME";
set -e _OLD_VIRTUAL_PYTHONHOME;
end;
# check if old prompt function exists
if functions -q _pyenv_old_prompt
# remove old prompt function if exists.
functions -e fish_prompt
functions -c _pyenv_old_prompt fish_prompt
functions -e _pyenv_old_prompt
end
if functions -q deactivate;
functions -e deactivate;
end;
@ -278,6 +293,13 @@ if [ -n "\$_OLD_VIRTUAL_PYTHONHOME" ];
set -gx PYTHONHOME "\$_OLD_VIRTUAL_PYTHONHOME";
set -e _OLD_VIRTUAL_PYTHONHOME;
end;
# check if old prompt function exists
if functions -q _pyenv_old_prompt
# remove old prompt function if exists.
functions -e fish_prompt
functions -c _pyenv_old_prompt fish_prompt
functions -e _pyenv_old_prompt
end
if functions -q deactivate;
functions -e deactivate;
end;
@ -306,6 +328,13 @@ if [ -n "\$_OLD_VIRTUAL_PYTHONHOME" ];
set -gx PYTHONHOME "\$_OLD_VIRTUAL_PYTHONHOME";
set -e _OLD_VIRTUAL_PYTHONHOME;
end;
# check if old prompt function exists
if functions -q _pyenv_old_prompt
# remove old prompt function if exists.
functions -e fish_prompt
functions -c _pyenv_old_prompt fish_prompt
functions -e _pyenv_old_prompt
end
if functions -q deactivate;
functions -e deactivate;
end;
@ -332,6 +361,13 @@ if [ -n "\$_OLD_VIRTUAL_PYTHONHOME" ];
set -gx PYTHONHOME "\$_OLD_VIRTUAL_PYTHONHOME";
set -e _OLD_VIRTUAL_PYTHONHOME;
end;
# check if old prompt function exists
if functions -q _pyenv_old_prompt
# remove old prompt function if exists.
functions -e fish_prompt
functions -c _pyenv_old_prompt fish_prompt
functions -e _pyenv_old_prompt
end
if functions -q deactivate;
functions -e deactivate;
end;

View file

@ -25,15 +25,15 @@ unstub_pyenv() {
stub pyenv-version-name "echo '${PYENV_VERSION}'"
stub pyenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'"
stub pyenv-virtualenv-prefix " : false"
stub pyenv-exec "python3.5 -m venv --help : true"
stub pyenv-exec "python3.5 -m venv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\";mkdir -p \${PYENV_ROOT}/versions/3.5.1/envs/venv/bin"
stub pyenv-exec "python -m venv --help : true"
stub pyenv-exec "python -m venv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\";mkdir -p \${PYENV_ROOT}/versions/3.5.1/envs/venv/bin"
stub pyenv-exec "python -s -m ensurepip : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\";touch \${PYENV_ROOT}/versions/3.5.1/envs/venv/bin/pip"
run pyenv-virtualenv venv
assert_success
assert_output <<OUT
PYENV_VERSION=3.5.1 python3.5 -m venv ${PYENV_ROOT}/versions/3.5.1/envs/venv
PYENV_VERSION=3.5.1 python -m venv ${PYENV_ROOT}/versions/3.5.1/envs/venv
PYENV_VERSION=3.5.1/envs/venv python -s -m ensurepip
rehashed
OUT

View file

@ -6,6 +6,7 @@ setup() {
export PYENV_ROOT="${TMP}/pyenv"
export HOOK_PATH="${TMP}/i has hooks"
mkdir -p "$HOOK_PATH"
unset PYENV_VIRTUALENV_PROMPT
}
@test "pyenv-virtualenv hooks" {
@ -17,7 +18,7 @@ OUT
create_executable "3.5.1" "virtualenv"
stub pyenv-prefix "echo '${PYENV_ROOT}/versions/3.5.1'"
stub pyenv-prefix "echo '${PYENV_ROOT}/versions/3.5.1'"
stub pyenv-exec "python3.5 -m venv --help : true"
stub pyenv-exec "python -m venv --help : true"
stub pyenv-hooks "virtualenv : echo '$HOOK_PATH'/virtualenv.bash"
stub pyenv-exec "echo PYENV_VERSION=3.5.1 \"\$@\""
stub pyenv-exec "echo PYENV_VERSION=3.5.1 \"\$@\""
@ -40,3 +41,74 @@ OUT
unstub pyenv-rehash
teardown_version "3.5.1"
}
@test "pyenv-sh-activate hooks" {
cat > "${HOOK_PATH}/activate.bash" <<OUT
before_activate 'echo "before"'
after_activate 'echo "after"'
OUT
export PYENV_VIRTUALENV_INIT=1
stub pyenv-version-name "echo venv"
stub pyenv-virtualenv-prefix ""
stub pyenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\""
stub pyenv-hooks "activate : echo '$HOOK_PATH'/activate.bash"
stub pyenv-sh-deactivate ""
PYENV_SHELL="bash" PYENV_VERSION="venv" run pyenv-sh-activate
assert_success
assert_output <<EOS
before
export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv";
export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv";
export _OLD_VIRTUAL_PS1="\${PS1:-}";
export PS1="(venv) \${PS1:-}";
after
EOS
unstub pyenv-version-name
unstub pyenv-virtualenv-prefix
unstub pyenv-prefix
unstub pyenv-hooks
unstub pyenv-sh-deactivate
}
@test "deactivate virtualenv" {
cat > "${HOOK_PATH}/deactivate.bash" <<OUT
before_deactivate 'echo "before"'
after_deactivate 'echo "after"'
OUT
export PYENV_VIRTUALENV_INIT=1
export PYENV_VIRTUAL_ENV="${PYENV_ROOT}/versions/venv"
export VIRTUAL_ENV="${PYENV_ROOT}/versions/venv"
export PYENV_ACTIVATE_SHELL=
stub pyenv-hooks "deactivate : echo '$HOOK_PATH'/deactivate.bash"
PYENV_SHELL="bash" run pyenv-sh-deactivate
assert_success
assert_output <<EOS
before
unset PYENV_VIRTUAL_ENV;
unset VIRTUAL_ENV;
if [ -n "\${_OLD_VIRTUAL_PATH:-}" ]; then
export PATH="\${_OLD_VIRTUAL_PATH}";
unset _OLD_VIRTUAL_PATH;
fi;
if [ -n "\${_OLD_VIRTUAL_PYTHONHOME:-}" ]; then
export PYTHONHOME="\${_OLD_VIRTUAL_PYTHONHOME}";
unset _OLD_VIRTUAL_PYTHONHOME;
fi;
if [ -n "\${_OLD_VIRTUAL_PS1:-}" ]; then
export PS1="\${_OLD_VIRTUAL_PS1}";
unset _OLD_VIRTUAL_PS1;
fi;
if declare -f deactivate 1>/dev/null 2>&1; then
unset -f deactivate;
fi;
after
EOS
unstub pyenv-hooks
}

View file

@ -29,22 +29,18 @@ load test_helper
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 "other shells instructions" {
run pyenv-virtualenv-init some_other_sh
assert [ "$status" -eq 1 ]
assert_output_contains 'eval "$(pyenv virtualenv-init -)"'
}
@test "outputs bash-specific syntax" {
export PYENV_VIRTUALENV_ROOT="${TMP}/pyenv/plugins/pyenv-virtualenv"
run pyenv-virtualenv-init - bash
@ -54,11 +50,44 @@ export PATH="${TMP}/pyenv/plugins/pyenv-virtualenv/shims:\${PATH}";
export PYENV_VIRTUALENV_INIT=1;
_pyenv_virtualenv_hook() {
local ret=\$?
if [ "\${PYENV_VERSION-}" = "\${_PYENV_VH_VERSION-}" ] \\
&& [ "\${VIRTUAL_ENV-}" = "\${_PYENV_VH_VENV-}" ]; then
if [ -n "\${PYENV_VERSION-}" ]; then
return \$ret
fi
if [ "\${PWD}" = "\${_PYENV_VH_PWD-}" ] \\
&& [ "\$(stat ${_stat_fmt} "\${_PYENV_VH_PATHS[@]}" 2>/dev/null)" = "\${_PYENV_VH_MTIMES-}" ]; then
return \$ret
fi
fi
if [ -n "\${VIRTUAL_ENV-}" ]; then
eval "\$(pyenv sh-activate --quiet || pyenv sh-deactivate --quiet || true)" || true
else
eval "\$(pyenv sh-activate --quiet || true)" || true
fi
_PYENV_VH_PWD="\${PWD}"
_PYENV_VH_VERSION="\${PYENV_VERSION-}"
_PYENV_VH_VENV="\${VIRTUAL_ENV-}"
local _pvh_d="\${PWD}" _pvh_found_local=0
_PYENV_VH_PATHS=()
while :; do
if [ -f "\${_pvh_d}/.python-version" ] || [ -L "\${_pvh_d}/.python-version" ]; then
_PYENV_VH_PATHS+=("\${_pvh_d}/.python-version")
if [ -f "\${_pvh_d}/.python-version" ]; then
_pvh_found_local=1
break
fi
else
_PYENV_VH_PATHS+=("\${_pvh_d}")
fi
[ "\${_pvh_d}" = "/" ] && break
_pvh_d="\${_pvh_d%/*}"
[ -z "\${_pvh_d}" ] && _pvh_d="/"
done
if [ "\${_pvh_found_local}" = "0" ]; then
_PYENV_VH_PATHS+=("\${PYENV_ROOT}/version")
fi
_PYENV_VH_MTIMES="\$(stat ${_stat_fmt} "\${_PYENV_VH_PATHS[@]}" 2>/dev/null)"
return \$ret
};
if ! [[ "\${PROMPT_COMMAND-}" =~ _pyenv_virtualenv_hook ]]; then
@ -78,11 +107,45 @@ set -gx PATH '${TMP}/pyenv/plugins/pyenv-virtualenv/shims' \$PATH;
set -gx PYENV_VIRTUALENV_INIT 1;
function _pyenv_virtualenv_hook --on-event fish_prompt;
set -l ret \$status
if test "\$PYENV_VERSION" = "\$_PYENV_VH_VERSION" \\
-a "\$VIRTUAL_ENV" = "\$_PYENV_VH_VENV"
if test -n "\$PYENV_VERSION"
return \$ret
end
if test "\$PWD" = "\$_PYENV_VH_PWD" \\
-a "(stat ${_stat_fmt} \$_PYENV_VH_PATHS 2>/dev/null)" = "\$_PYENV_VH_MTIMES"
return \$ret
end
end
if [ -n "\$VIRTUAL_ENV" ]
pyenv activate --quiet; or pyenv deactivate --quiet; or true
else
pyenv activate --quiet; or true
end
set -g _PYENV_VH_PWD "\$PWD"
set -g _PYENV_VH_VERSION "\$PYENV_VERSION"
set -g _PYENV_VH_VENV "\$VIRTUAL_ENV"
set -l d "\$PWD"
set -l _pvh_found_local 0
set -g _PYENV_VH_PATHS
while true
if test -f "\$d/.python-version"; or test -L "\$d/.python-version"
set -g _PYENV_VH_PATHS \$_PYENV_VH_PATHS "\$d/.python-version"
if test -f "\$d/.python-version"
set _pvh_found_local 1
break
end
else
set -g _PYENV_VH_PATHS \$_PYENV_VH_PATHS "\$d"
end
test "\$d" = "/"; and break
set d (string replace -r '/[^/]*\$' '' -- "\$d")
test -z "\$d"; and set d "/"
end
if test "\$_pvh_found_local" = "0"
set -g _PYENV_VH_PATHS \$_PYENV_VH_PATHS "\$PYENV_ROOT/version"
end
set -g _PYENV_VH_MTIMES (stat ${_stat_fmt} \$_PYENV_VH_PATHS 2>/dev/null)
return \$ret
end
EOS
@ -97,11 +160,44 @@ export PATH="${TMP}/pyenv/plugins/pyenv-virtualenv/shims:\${PATH}";
export PYENV_VIRTUALENV_INIT=1;
_pyenv_virtualenv_hook() {
local ret=\$?
if [ "\${PYENV_VERSION-}" = "\${_PYENV_VH_VERSION-}" ] \\
&& [ "\${VIRTUAL_ENV-}" = "\${_PYENV_VH_VENV-}" ]; then
if [ -n "\${PYENV_VERSION-}" ]; then
return \$ret
fi
if [ "\${PWD}" = "\${_PYENV_VH_PWD-}" ] \\
&& [ "\$(stat ${_stat_fmt} "\${_PYENV_VH_PATHS[@]}" 2>/dev/null)" = "\${_PYENV_VH_MTIMES-}" ]; then
return \$ret
fi
fi
if [ -n "\${VIRTUAL_ENV-}" ]; then
eval "\$(pyenv sh-activate --quiet || pyenv sh-deactivate --quiet || true)" || true
else
eval "\$(pyenv sh-activate --quiet || true)" || true
fi
_PYENV_VH_PWD="\${PWD}"
_PYENV_VH_VERSION="\${PYENV_VERSION-}"
_PYENV_VH_VENV="\${VIRTUAL_ENV-}"
local _pvh_d="\${PWD}" _pvh_found_local=0
_PYENV_VH_PATHS=()
while :; do
if [ -f "\${_pvh_d}/.python-version" ] || [ -L "\${_pvh_d}/.python-version" ]; then
_PYENV_VH_PATHS+=("\${_pvh_d}/.python-version")
if [ -f "\${_pvh_d}/.python-version" ]; then
_pvh_found_local=1
break
fi
else
_PYENV_VH_PATHS+=("\${_pvh_d}")
fi
[ "\${_pvh_d}" = "/" ] && break
_pvh_d="\${_pvh_d%/*}"
[ -z "\${_pvh_d}" ] && _pvh_d="/"
done
if [ "\${_pvh_found_local}" = "0" ]; then
_PYENV_VH_PATHS+=("\${PYENV_ROOT}/version")
fi
_PYENV_VH_MTIMES="\$(stat ${_stat_fmt} "\${_PYENV_VH_PATHS[@]}" 2>/dev/null)"
return \$ret
};
typeset -g -a precmd_functions
@ -110,3 +206,13 @@ if [[ -z \$precmd_functions[(r)_pyenv_virtualenv_hook] ]]; then
fi
EOS
}
@test "outputs other shells syntax" {
export PYENV_VIRTUALENV_ROOT="${TMP}/pyenv/plugins/pyenv-virtualenv"
run pyenv-virtualenv-init - some_other_sh
assert_success
assert_output <<EOS
export PATH="${TMP}/pyenv/plugins/pyenv-virtualenv/shims:\${PATH}";
export PYENV_VIRTUALENV_INIT=1;
EOS
}

View file

@ -26,15 +26,16 @@ unstub_pyenv() {
stub_pyenv "${PYENV_VERSION}"
stub pyenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'"
stub pyenv-virtualenv-prefix " : false"
stub pyenv-exec "python3.5 -m venv --help : true"
stub pyenv-exec "python3.5 -m venv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\";mkdir -p \${PYENV_ROOT}/versions/3.5.1/envs/venv/bin"
stub pyenv-exec "python -m venv --help : true"
stub pyenv-exec "python -m venv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\";mkdir -p \${PYENV_ROOT}/versions/3.5.1/envs/venv/bin"
stub pyenv-exec "python -s -m ensurepip : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\";touch \${PYENV_ROOT}/versions/3.5.1/envs/venv/bin/pip"
run pyenv-virtualenv venv
assert_success
assert_output <<OUT
PYENV_VERSION=3.5.1 python3.5 -m venv ${PYENV_ROOT}/versions/3.5.1/envs/venv
PYENV_VERSION=3.5.1 python -m venv ${TMP}/pyenv/versions/3.5.1/envs/venv
PYENV_VERSION=3.5.1/envs/venv python -s -m ensurepip
rehashed
OUT
@ -52,8 +53,8 @@ OUT
stub_pyenv "${PYENV_VERSION}"
stub pyenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'"
stub pyenv-virtualenv-prefix " : false"
stub pyenv-exec "python3.3 -m venv --help : true"
stub pyenv-exec "python3.3 -m venv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\";mkdir -p \${PYENV_ROOT}/versions/3.3.6/envs/venv/bin"
stub pyenv-exec "python -m venv --help : true"
stub pyenv-exec "python -m venv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\";mkdir -p \${PYENV_ROOT}/versions/3.3.6/envs/venv/bin"
stub pyenv-exec "python -s -m ensurepip : false"
stub pyenv-exec "python -s */get-pip.py : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\";touch \${PYENV_ROOT}/versions/3.3.6/envs/venv/bin/pip"
stub curl true
@ -62,7 +63,7 @@ OUT
assert_success
assert_output <<OUT
PYENV_VERSION=3.3.6 python3.3 -m venv ${PYENV_ROOT}/versions/3.3.6/envs/venv
PYENV_VERSION=3.3.6 python -m venv ${PYENV_ROOT}/versions/3.3.6/envs/venv
Installing pip from https://bootstrap.pypa.io/pip/3.3/get-pip.py...
PYENV_VERSION=3.3.6/envs/venv python -s ${TMP}/pyenv/cache/get-pip.py
rehashed

View file

@ -12,10 +12,6 @@ create_version() {
chmod +x "${PYENV_ROOT}/versions/$1/bin/python"
}
remove_version() {
rm -fr "${PYENV_ROOT}/versions/$1"
}
create_virtualenv() {
create_version "$1"
create_version "${2:-$1}"
@ -40,11 +36,6 @@ create_virtualenv_pypy() {
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}"
@ -52,10 +43,6 @@ create_m_venv() {
touch "${PYENV_ROOT}/versions/$1/bin/activate"
}
remove_m_venv() {
remove_version "${2:-$1}"
}
create_conda() {
create_version "$1"
create_version "${2:-$1}"
@ -66,13 +53,8 @@ create_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
@ -83,13 +65,10 @@ ${PYENV_ROOT}/versions/2.7.11
OUT
unstub pyenv-version-name
unstub pyenv-prefix
remove_virtualenv "foo" "2.7.11"
}
@test "display prefix of virtualenv created by virtualenv (pypy)" {
stub pyenv-version-name "echo foo"
stub pyenv-prefix "foo : echo \"${PYENV_ROOT}/versions/foo\""
create_virtualenv_pypy "foo" "pypy-4.0.1"
PYENV_VERSION="foo" run pyenv-virtualenv-prefix
@ -100,13 +79,10 @@ ${PYENV_ROOT}/versions/pypy-4.0.1
OUT
unstub pyenv-version-name
unstub pyenv-prefix
remove_virtualenv "foo" "pypy-4.0.1"
}
@test "display prefix of virtualenv created by virtualenv (jython)" {
stub pyenv-version-name "echo foo"
stub pyenv-prefix "foo : echo \"${PYENV_ROOT}/versions/foo\""
create_virtualenv_jython "foo" "jython-2.7.0"
PYENV_VERSION="foo" run pyenv-virtualenv-prefix
@ -117,14 +93,10 @@ ${PYENV_ROOT}/versions/jython-2.7.0
OUT
unstub pyenv-version-name
unstub pyenv-prefix
remove_virtualenv "foo" "jython-2.7.0"
}
@test "display prefixes of virtualenv created by virtualenv" {
stub pyenv-version-name "echo foo:bar"
stub pyenv-prefix "foo : echo \"${PYENV_ROOT}/versions/foo\"" \
"bar : echo \"${PYENV_ROOT}/versions/bar\""
create_virtualenv "foo" "2.7.11"
create_virtualenv "bar" "3.5.1"
@ -136,14 +108,10 @@ ${PYENV_ROOT}/versions/2.7.11:${PYENV_ROOT}/versions/3.5.1
OUT
unstub pyenv-version-name
unstub pyenv-prefix
remove_virtualenv "foo" "2.7.11"
remove_virtualenv "bar" "3.5.1"
}
@test "display prefix of virtualenv created by venv" {
stub pyenv-version-name "echo foo"
stub pyenv-prefix "foo : echo \"${PYENV_ROOT}/versions/foo\""
create_m_venv "foo" "3.3.6"
PYENV_VERSION="foo" run pyenv-virtualenv-prefix
@ -154,14 +122,10 @@ ${PYENV_ROOT}/versions/3.3.6
OUT
unstub pyenv-version-name
unstub pyenv-prefix
remove_m_venv "foo" "3.3.6"
}
@test "display prefixes of virtualenv created by venv" {
stub pyenv-version-name "echo foo:bar"
stub pyenv-prefix "foo : echo \"${PYENV_ROOT}/versions/foo\"" \
"bar : echo \"${PYENV_ROOT}/versions/bar\""
create_m_venv "foo" "3.3.6"
create_m_venv "bar" "3.4.4"
@ -173,14 +137,10 @@ ${PYENV_ROOT}/versions/3.3.6:${PYENV_ROOT}/versions/3.4.4
OUT
unstub pyenv-version-name
unstub pyenv-prefix
remove_m_venv "foo" "3.3.6"
remove_m_venv "bar" "3.4.4"
}
@test "display prefix of virtualenv created by conda" {
stub pyenv-version-name "echo miniconda3-3.16.0/envs/foo"
stub pyenv-prefix "miniconda3-3.16.0/envs/foo : echo \"${PYENV_ROOT}/versions/miniconda3-3.16.0/envs/foo\""
create_conda "miniconda3-3.16.0/envs/foo" "miniconda3-3.16.0"
PYENV_VERSION="miniconda3-3.16.0/envs/foo" run pyenv-virtualenv-prefix
@ -191,8 +151,6 @@ ${PYENV_ROOT}/versions/miniconda3-3.16.0/envs/foo
OUT
unstub pyenv-version-name
unstub pyenv-prefix
remove_conda "miniconda3-3.16.0/envs/foo" "miniconda3-3.16.0"
}
@test "should fail if the version is the system" {
@ -210,7 +168,6 @@ OUT
@test "should fail if the version is not a virtualenv" {
stub pyenv-version-name "echo 3.4.4"
stub pyenv-prefix "3.4.4 : echo \"${PYENV_ROOT}/versions/3.4.4\""
create_version "3.4.4"
PYENV_VERSION="3.4.4" run pyenv-virtualenv-prefix
@ -221,14 +178,10 @@ pyenv-virtualenv: version \`3.4.4' is not a virtualenv
OUT
unstub pyenv-version-name
unstub pyenv-prefix
remove_version "3.4.4"
}
@test "should fail if one of the versions is not a virtualenv" {
stub pyenv-version-name "echo venv33:3.4.4"
stub pyenv-prefix "venv33 : echo \"${PYENV_ROOT}/versions/venv33\"" \
"3.4.4 : echo \"${PYENV_ROOT}/versions/3.4.4\""
create_virtualenv "venv33" "3.3.6"
create_version "3.4.4"
@ -240,7 +193,22 @@ pyenv-virtualenv: version \`3.4.4' is not a virtualenv
OUT
unstub pyenv-version-name
unstub pyenv-prefix
remove_virtualenv "venv33" "3.3.6"
remove_version "3.4.4"
}
@test "resolves a version that is not an exact match" {
stub pyenv-version-name "echo 3"
create_version "3.4.4"
stub pyenv-prefix "3 : echo \"$PYENV_ROOT/versions/3.4.4\""
run pyenv-virtualenv-prefix
assert_failure
assert_output <<OUT
pyenv-virtualenv: version \`3' is not a virtualenv
OUT
unstub pyenv-version-name
unstub pyenv-prefix
}

View file

@ -14,6 +14,7 @@ setup() {
stub pyenv-rehash " : true"
stub pyenv-version-name "echo \${PYENV_VERSION}"
stub curl true
stub python-build "echo python2.7"
}
teardown() {
@ -22,6 +23,7 @@ teardown() {
unstub pyenv-prefix
unstub pyenv-hooks
unstub pyenv-rehash
unstub python-build
teardown_version "2.7.8"
rm -fr "$TMP"/*
}
@ -31,8 +33,6 @@ teardown() {
create_executable "2.7.8" "python2.7"
remove_executable "2.7.9" "python2.7"
stub pyenv-exec "python2.7 -m venv --help : false"
stub pyenv-exec "python2 -m venv --help : false"
stub pyenv-exec "python -m venv --help : false"
stub pyenv-exec "virtualenv --verbose * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "python -s -m ensurepip : true"
@ -40,13 +40,13 @@ teardown() {
run pyenv-virtualenv --verbose --python=python2.7 venv
unstub pyenv-exec
assert_output <<OUT
PYENV_VERSION=2.7.8 virtualenv --verbose --python=${PYENV_ROOT}/versions/2.7.8/bin/python2.7 ${PYENV_ROOT}/versions/2.7.8/envs/venv
OUT
assert_success
unstub pyenv-which
unstub pyenv-exec
remove_executable "2.7.7" "python2.7"
remove_executable "2.7.8" "python2.7"
@ -58,8 +58,6 @@ OUT
remove_executable "2.7.8" "python2.7"
create_executable "2.7.9" "python2.7"
stub pyenv-exec "python2.7 -m venv --help : false"
stub pyenv-exec "python2 -m venv --help : false"
stub pyenv-exec "python -m venv --help : false"
stub pyenv-exec "virtualenv --verbose * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "python -s -m ensurepip : true"
@ -96,6 +94,7 @@ OUT
assert_output <<OUT
pyenv-virtualenv: \`python2.7' is not installed in pyenv.
Run \`pyenv install python2.7' to install it.
OUT
assert_failure
@ -106,3 +105,13 @@ OUT
remove_executable "2.7.8" "python2.7"
remove_executable "2.7.9" "python2.7"
}
@test "invalid python name" {
run pyenv-virtualenv --verbose --python=99.99.99 venv
assert_output <<OUT
pyenv-virtualenv: \`99.99.99' is not installed in pyenv.
It does not look like a valid Python version. See \`pyenv install --list' for available versions.
OUT
assert_failure
}

View file

@ -26,14 +26,14 @@ unstub_pyenv() {
stub_pyenv "${PYENV_VERSION}"
stub pyenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'"
stub pyenv-virtualenv-prefix " : false"
stub pyenv-exec "python3.5 -m venv --help : true"
stub pyenv-exec "python3.5 -m venv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "python -m venv --help : true"
stub pyenv-exec "python -m venv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "python -s -m ensurepip : true"
run pyenv-virtualenv venv
assert_output <<OUT
PYENV_VERSION=3.5.1 python3.5 -m venv ${PYENV_ROOT}/versions/3.5.1/envs/venv
PYENV_VERSION=3.5.1 python -m venv ${PYENV_ROOT}/versions/3.5.1/envs/venv
rehashed
OUT
assert [ -x "${PYENV_ROOT}/versions/3.5.1/envs/venv/bin/pydoc" ]
@ -52,7 +52,7 @@ OUT
stub_pyenv "${PYENV_VERSION}"
stub pyenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'"
stub pyenv-virtualenv-prefix " : false"
stub pyenv-exec "python3.5 -m venv --help : true"
stub pyenv-exec "python -m venv --help : true"
stub pyenv-exec "virtualenv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "python -s -m ensurepip : true"
@ -77,8 +77,6 @@ OUT
stub_pyenv "${PYENV_VERSION}"
stub pyenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'"
stub pyenv-virtualenv-prefix " : false"
stub pyenv-exec "python3.2 -m venv --help : false"
stub pyenv-exec "python3 -m venv --help : false"
stub pyenv-exec "python -m venv --help : false"
stub pyenv-exec "pip install virtualenv* : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "virtualenv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
@ -105,7 +103,7 @@ OUT
stub_pyenv "${PYENV_VERSION}"
stub pyenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'"
stub pyenv-virtualenv-prefix " : false"
stub pyenv-exec "python3.5 -m venv --help : true"
stub pyenv-exec "python -m venv --help : true"
stub pyenv-exec "pip install virtualenv : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "virtualenv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "python -s -m ensurepip : true"
@ -132,7 +130,7 @@ OUT
stub_pyenv "${PYENV_VERSION}"
stub pyenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'"
stub pyenv-virtualenv-prefix " : false"
stub pyenv-exec "python3.5 -m venv --help : true"
stub pyenv-exec "python -m venv --help : true"
stub pyenv-exec "pip install virtualenv : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "virtualenv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "python -s -m ensurepip : true"
@ -159,8 +157,6 @@ OUT
stub_pyenv "${PYENV_VERSION}"
stub pyenv-prefix " : echo '${PYENV_ROOT}/versions/${PYENV_VERSION}'"
stub pyenv-virtualenv-prefix " : false"
stub pyenv-exec "python3.2 -m venv --help : false"
stub pyenv-exec "python3 -m venv --help : false"
stub pyenv-exec "python -m venv --help : false"
stub pyenv-exec "pip install virtualenv* : echo PIP_REQUIRE_VENV=\${PIP_REQUIRE_VENV} PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "virtualenv * : echo PIP_REQUIRE_VENV=\${PIP_REQUIRE_VENV} PYENV_VERSION=\${PYENV_VERSION} \"\$@\""

View file

@ -1,4 +1,5 @@
#!/usr/bin/env bash
export PS4='+($$:${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
set -e
status=0
@ -6,41 +7,158 @@ program="${0##*/}"
PROGRAM="$(echo "$program" | tr a-z- A-Z_)"
[ -n "$TMPDIR" ] || TMPDIR="/tmp"
_STUB_PLAN="${PROGRAM}_STUB_PLAN"
_STUB_RUN="${PROGRAM}_STUB_RUN"
_STUB_INDEX="${PROGRAM}_STUB_INDEX"
_STUB_RESULT="${PROGRAM}_STUB_RESULT"
_STUB_END="${PROGRAM}_STUB_END"
_STUB_DEBUG="${PROGRAM}_STUB_DEBUG"
STUB_PLAN="${PROGRAM}_STUB_PLAN"
STUB_PLAN="${!STUB_PLAN}"
if [ -n "${!_STUB_DEBUG}" ]; then
echo "$program" "$@" >&${!_STUB_DEBUG}
fi
STUB_RUN="${PROGRAM}_STUB_RUN"
STUB_RUN="${!STUB_RUN:-${TMPDIR}/${program}-stub-run}"
STUB_INDEX=
STUB_RESULT=
[ -e "${!_STUB_PLAN}" ] || exit 1
[ -n "${!_STUB_RUN}" ] || eval "${_STUB_RUN}"="${TMPDIR}/${program}-stub-run"
STUB_END="${PROGRAM}_STUB_END"
STUB_END="${!STUB_END}"
STUB_LOG="${PROGRAM}_STUB_LOG"
STUB_LOG="${!STUB_LOG:-${TMPDIR}/${program}-stub-log}"
STUB_LOCKFILE="${TMPDIR}/${program}-stub.lock"
release_lock() {
rm -f "$STUB_LOCKFILE"
trap - EXIT
}
acquire_lock() {
local start=$SECONDS
local acquire_timeout=10
local acquired=
while (( SECONDS <= start + $acquire_timeout )); do
( set -o noclobber; echo -n >"$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.
eval "${_STUB_INDEX}"=1
eval "${_STUB_RESULT}"=0
[ ! -e "${!_STUB_RUN}" ] || source "${!_STUB_RUN}"
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" <etc>)"
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='(<value>)' createss "([0]='<value>')" rather than duplicate the array
if [[ ${data:0:1} == "'" && ${data:${#data}-1:1} == "'" ]]; then
data="${data:1:${#data}-2}"
fi
eval "$dest=$data"
}
# Loop over each line in the plan.
index=0
while IFS= read -r line; do
index=$(($index + 1))
if [ -z "${!_STUB_END}" ] && [ $index -eq "${!_STUB_INDEX}" ]; then
# We found the plan line we're interested in.
# Start off by assuming success.
result=0
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" != "${command/ : }" ]; then
if [[ $command == *" : "* ]]; then
patterns="${command%% : *}"
command="${command#* : }"
fi
@ -55,55 +173,110 @@ while IFS= read -r line; do
# 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 ) ;;
* ) result=1 ;;
* ) match_result=1 ;;
esac
done
# If the arguments matched, evaluate the command
# in a subshell. Otherwise, log the failure.
if [ $result -eq 0 ] ; then
set +e
( eval "$command" )
status="$?"
set -e
else
eval "${_STUB_RESULT}"=1
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
done < "${!_STUB_PLAN}"
if [ -n "${!_STUB_END}" ]; then
# Clean up the run file.
rm -f "${!_STUB_RUN}"
# If the number of lines in the plan is larger than
# the requested index, we failed.
if [ $index -ge "${!_STUB_INDEX}" ]; then
eval "${_STUB_RESULT}"=1
fi
# Return the result.
exit "${!_STUB_RESULT}"
else
# If the requested index is larger than the number
# of lines in the plan file, we failed.
if [ "${!_STUB_INDEX}" -gt $index ]; then
eval "${_STUB_RESULT}"=1
fi
# Write out the run information.
{ echo "${_STUB_INDEX}=$((${!_STUB_INDEX} + 1))"
echo "${_STUB_RESULT}=${!_STUB_RESULT}"
} > "${!_STUB_RUN}"
# 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

View file

@ -1,6 +1,15 @@
export TMP="$BATS_TEST_DIRNAME/tmp"
PATH=/usr/bin:/usr/sbin:/bin/:/sbin
# Detect stat format for mtime: GNU uses -c %Y, BSD uses -f %m
# Must match the detection in bin/pyenv-virtualenv-init
if stat -L -c %Y / >/dev/null 2>&1; then
_stat_fmt="-L -c %Y"
else
_stat_fmt="-L -f %m"
fi
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
@ -10,19 +19,51 @@ teardown() {
}
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 printf "%s\n" "$arg" >> "${TMP}/${program}-stub-plan"; done
for arg in "$@"; do
echo "$FLAGS" "$arg" >> "${TMP}/${program}-stub-plan"
done
}
unstub() {
@ -82,6 +123,16 @@ assert_equal() {
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 -)"
@ -90,6 +141,14 @@ assert_output() {
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 || {
@ -170,3 +229,4 @@ setup_conda() {
teardown_conda() {
rm -fr "${PYENV_ROOT}/versions/$1"
}

View file

@ -10,8 +10,6 @@ setup() {
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 "python2.7 -m venv --help : false"
stub pyenv-exec "python2 -m venv --help : false"
stub pyenv-exec "python -m venv --help : false"
stub pyenv-exec "virtualenv --version : echo \"1.11\""
@ -29,12 +27,12 @@ setup() {
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 "python3.4 -m venv --help : true"
stub pyenv-exec "python -m venv --help : true"
run pyenv-virtualenv --version
assert_success
[[ "$output" == "pyenv-virtualenv "?.?.?" (python3.4 -m venv)" ]]
[[ "$output" == "pyenv-virtualenv "?.?.?" (python -m venv)" ]]
unstub pyenv-prefix
teardown_m_venv "3.4.1"

View file

@ -26,13 +26,14 @@ unstub_pyenv() {
export PYENV_VERSION="2.7.11"
stub_pyenv "${PYENV_VERSION}"
stub pyenv-virtualenv-prefix " : false"
stub pyenv-exec "python2.7 -m venv --help : false"
stub pyenv-exec "python2 -m venv --help : false"
stub pyenv-exec "python -m venv --help : false"
stub pyenv-exec "virtualenv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
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"
@ -41,8 +42,10 @@ PYENV_VERSION=2.7.11 virtualenv ${PYENV_ROOT}/versions/2.7.11/envs/venv
Installing pip from https://bootstrap.pypa.io/pip/2.7/get-pip.py...
rehashed
OUT
assert [ -x "${PYENV_ROOT}/versions/2.7.11/envs/venv/bin/pydoc" ]
assert_success
for x in pydoc python-config python2-config python2.7-config; do
assert [ -x "${PYENV_ROOT}/versions/2.7.11/envs/venv/bin/$x" ]
done
unstub_pyenv
unstub pyenv-virtualenv-prefix
@ -53,14 +56,12 @@ OUT
@test "create virtualenv from a given prefix" {
stub_pyenv "2.7.11"
stub pyenv-virtualenv-prefix " : false"
stub pyenv-exec "python2.7 -m venv --help : false"
stub pyenv-exec "python2 -m venv --help : false"
stub pyenv-exec "python -m venv --help : false"
stub pyenv-exec "virtualenv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "python -s -m ensurepip : false"
stub pyenv-exec "python -s */get-pip.py : true"
stub curl true
stub pyenv-latest "-q 2.7 : echo 2.7.11"
stub pyenv-latest "-f 2.7 : echo 2.7.11"
run pyenv-virtualenv "2.7" "venv"
@ -84,8 +85,6 @@ OUT
stub_pyenv "${PYENV_VERSION}"
stub pyenv-version-name "echo \${PYENV_VERSION}"
stub pyenv-virtualenv-prefix " : false"
stub pyenv-exec "python2.7 -m venv --help : false"
stub pyenv-exec "python2 -m venv --help : false"
stub pyenv-exec "python -m venv --help : false"
stub pyenv-exec "virtualenv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "python -s -m ensurepip : false"
@ -114,8 +113,6 @@ OUT
stub_pyenv "${PYENV_VERSION}"
stub pyenv-version-name "echo \${PYENV_VERSION}"
stub pyenv-virtualenv-prefix " : false"
stub pyenv-exec "python2.7 -m venv --help : false"
stub pyenv-exec "python2 -m venv --help : false"
stub pyenv-exec "python -m venv --help : false"
stub pyenv-exec "virtualenv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "python -s -m ensurepip : false"
@ -144,8 +141,6 @@ OUT
stub_pyenv "${PYENV_VERSION}"
stub pyenv-version-name "echo \${PYENV_VERSION}"
stub pyenv-virtualenv-prefix " : false"
stub pyenv-exec "python2.7 -m venv --help : false"
stub pyenv-exec "python2 -m venv --help : false"
stub pyenv-exec "python -m venv --help : false"
stub pyenv-exec "virtualenv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "python -s -m ensurepip : false"
@ -209,8 +204,6 @@ OUT
export PYENV_VERSION="2.7.11"
stub_pyenv "${PYENV_VERSION}"
stub pyenv-virtualenv-prefix " : false"
stub pyenv-exec "python2.7 -m venv --help : false"
stub pyenv-exec "python2 -m venv --help : false"
stub pyenv-exec "python -m venv --help : false"
stub pyenv-exec "virtualenv * : echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\""
stub pyenv-exec "python -s -m ensurepip : false"

View file

@ -2,27 +2,79 @@
load test_helper
setup() {
export PYENV_ROOT="${TMP}/pyenv"
mkdir -p "${PYENV_ROOT}/versions/2.7.6"
mkdir -p "${PYENV_ROOT}/versions/3.3.3"
mkdir -p "${PYENV_ROOT}/versions/venv27"
mkdir -p "${PYENV_ROOT}/versions/venv33"
create_m_system_venv() {
# Create a mock virtual environment in the same way a venv created from
# the system Python version looks.
#
# The venv is in ${PYENV_ROOT}/versions, is not a symlink, and
# home is /usr/bin in the pyenv.cfg.
create_executable "$2" "python"
create_executable "$2" "activate"
local version="$1"
local venv="$2"
local venv_dir="${PYENV_ROOT}/versions/${venv}"
echo "home = /usr/bin" > "${venv_dir}/pyvenv.cfg"
}
@test "list virtual environments only" {
stub pyenv-version-name ": echo system"
stub pyenv-virtualenv-prefix "2.7.6 : false"
stub pyenv-virtualenv-prefix "3.3.3 : false"
stub pyenv-virtualenv-prefix "venv27 : echo \"${PYENV_ROOT}/versions/2.7.6\""
stub pyenv-virtualenv-prefix "venv33 : echo \"${PYENV_ROOT}/versions/3.3.3\""
create_m_venv() {
# Create a mock virtual environment from an installed (not system) Python version.
#
# The venv name is a symlink inside ${PYENV_ROOT}/versions that points to
# the real venv directory inside the Python version used to created and
# home points to the bin directory inside the venv dir.
setup_m_venv "$1/envs/$2"
local version="$1"
local venv="$2"
local venv_dir="${PYENV_ROOT}/versions/${version}/envs/${venv}"
echo "home = ${PYENV_ROOT}/versions/${version}/bin" > "${venv_dir}/pyvenv.cfg"
ln -sf "${venv_dir}" "${PYENV_ROOT}/versions/${venv}"
}
setup() {
export PYENV_ROOT="${TMP}/pyenv"
}
@test "system venv" {
stub pyenv-version-name ": echo venv314"
stub pyenv-version-origin ": echo PYENV_VERSION"
create_m_venv "3.14.3" "venv314"
create_m_system_venv "3.9.11" "system_venv"
run pyenv-virtualenvs
assert_success
assert_output <<OUT
venv27 (created from ${PYENV_ROOT}/versions/2.7.6)
venv33 (created from ${PYENV_ROOT}/versions/3.3.3)
3.14.3/envs/venv314 (created from ${PYENV_ROOT}/versions/3.14.3)
system_venv (created from /usr)
* venv314 --> ${PYENV_ROOT}/versions/3.14.3/envs/venv314 (set by PYENV_VERSION)
OUT
unstub pyenv-version-name
unstub pyenv-version-origin
}
@test "list virtual environments" {
stub pyenv-version-name ": echo system"
stub pyenv-virtualenv-prefix "2.7.6/envs/venv27 : echo \"${PYENV_ROOT}/versions/2.7.6\""
stub pyenv-virtualenv-prefix "3.3.3/envs/venv33 : echo \"${PYENV_ROOT}/versions/3.3.3\""
create_m_venv "2.7.6" "venv27"
create_m_venv "3.3.3" "venv33"
run pyenv-virtualenvs
assert_success
assert_output <<OUT
2.7.6/envs/venv27 (created from ${PYENV_ROOT}/versions/2.7.6)
3.3.3/envs/venv33 (created from ${PYENV_ROOT}/versions/3.3.3)
venv27 --> ${PYENV_ROOT}/versions/2.7.6/envs/venv27
venv33 --> ${PYENV_ROOT}/versions/3.3.3/envs/venv33
OUT
unstub pyenv-version-name
@ -30,37 +82,101 @@ OUT
}
@test "list virtual environments with hit prefix" {
stub pyenv-version-name ": echo venv33"
stub pyenv-virtualenv-prefix "2.7.6 : false"
stub pyenv-virtualenv-prefix "3.3.3 : false"
stub pyenv-virtualenv-prefix "venv27 : echo \"/usr\""
stub pyenv-virtualenv-prefix "venv33 : echo \"/usr\""
stub pyenv-version-name ": echo 3.3.3/envs/venv33"
stub pyenv-version-origin ": echo PYENV_VERSION"
create_m_venv "2.7.6" "venv27"
create_m_venv "3.3.3" "venv33"
run pyenv-virtualenvs
assert_success
assert_output <<OUT
venv27 (created from /usr)
* venv33 (created from /usr)
2.7.6/envs/venv27 (created from ${PYENV_ROOT}/versions/2.7.6)
* 3.3.3/envs/venv33 (created from ${PYENV_ROOT}/versions/3.3.3) (set by PYENV_VERSION)
venv27 --> ${PYENV_ROOT}/versions/2.7.6/envs/venv27
venv33 --> ${PYENV_ROOT}/versions/3.3.3/envs/venv33
OUT
unstub pyenv-version-name
unstub pyenv-virtualenv-prefix
unstub pyenv-version-origin
}
@test "list virtual environments with --bare" {
stub pyenv-virtualenv-prefix "2.7.6 : false"
stub pyenv-virtualenv-prefix "3.3.3 : false"
stub pyenv-virtualenv-prefix "venv27 : echo \"/usr\""
stub pyenv-virtualenv-prefix "venv33 : echo \"/usr\""
@test "list bare virtual environments" {
create_m_venv "2.7.6" "venv27"
create_m_venv "3.3.3" "venv33"
run pyenv-virtualenvs --bare
assert_success
assert_output <<OUT
2.7.6/envs/venv27
3.3.3/envs/venv33
venv27
venv33
OUT
unstub pyenv-virtualenv-prefix
}
@test "list bare virtual environments without aliases" {
create_m_venv "2.7.6" "venv27"
create_m_venv "3.3.3" "venv33"
run pyenv-virtualenvs --bare --skip-aliases
assert_success
assert_output <<OUT
2.7.6/envs/venv27
3.3.3/envs/venv33
OUT
}
@test "list virtual environments without aliases" {
stub pyenv-version-name ": echo system"
create_m_venv "2.7.6" "venv27"
create_m_venv "3.3.3" "venv33"
run pyenv-virtualenvs --skip-aliases
assert_success
assert_output <<OUT
2.7.6/envs/venv27 (created from ${PYENV_ROOT}/versions/2.7.6)
3.3.3/envs/venv33 (created from ${PYENV_ROOT}/versions/3.3.3)
OUT
unstub pyenv-version-name
}
@test "hit prefix matches alias version name" {
stub pyenv-version-name ": echo venv27"
stub pyenv-version-origin ": echo PYENV_VERSION"
create_m_venv "2.7.6" "venv27"
create_m_venv "3.3.3" "venv33"
run pyenv-virtualenvs
assert_success
assert_output <<OUT
2.7.6/envs/venv27 (created from ${PYENV_ROOT}/versions/2.7.6)
3.3.3/envs/venv33 (created from ${PYENV_ROOT}/versions/3.3.3)
* venv27 --> ${PYENV_ROOT}/versions/2.7.6/envs/venv27 (set by PYENV_VERSION)
venv33 --> ${PYENV_ROOT}/versions/3.3.3/envs/venv33
OUT
unstub pyenv-version-name
unstub pyenv-version-origin
}
@test "completions output" {
create_m_venv "2.7.6" "venv27"
create_m_venv "3.3.3" "venv33"
run pyenv-virtualenvs --complete
assert_success
assert_output <<OUT
--bare
--skip-aliases
OUT
}