Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve performance and output of pyenv virtualenvs #502

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

samdoran
Copy link

@samdoran samdoran commented Feb 13, 2025

The biggest change is reusing most of the code used for pyenv versions in pyenv virtualenvs. This dramatically improves performance while making the output consistent.

Related to #490. Maybe fixes the problem?

With 128 virtual environments, it currently takes about 13 seconds to run pyenv virtualenvs --bare.

> time pyenv virtualenvs --bare > /dev/null 2>&1

________________________________________________________
Executed in   13.14 secs    fish           external
   usr time    6.32 secs    0.33 millis    6.32 secs
   sys time    6.13 secs    2.19 millis    6.13 secs
Output
1brc
3.10.13/envs/instruct-lab
3.10.13/envs/parquet-compactor-3.10.13
3.10.14/envs/ipython-3.10.14
3.10.15/envs/ipython-3.10.15
3.10.7/envs/cherry_picker-3.10.7
3.10.9/envs/pyls-3.10.9
3.11.0/envs/argcomplete-3.11.0
3.11.0/envs/asciinema-3.11.0
3.11.0/envs/borg-3.11.0
3.11.0/envs/cherry_picker-3.11.0
3.11.0/envs/cookiecutter-3.11.0
3.11.0/envs/diceware-3.11.0
3.11.0/envs/flake8-3.11.0
3.11.0/envs/ipdb-3.11.0
3.11.0/envs/isort-3.11.0
3.11.0/envs/jello-3.11.0
3.11.0/envs/mackup-3.11.0
3.11.0/envs/maestral-3.11.0
3.11.0/envs/mitmproxy-3.11.0
3.11.0/envs/mypy-3.11.0
3.11.0/envs/pipfile2req-3.11.0
3.11.0/envs/pur-3.11.0
3.11.0/envs/pylint-3.11.0
3.11.0/envs/pyspy-3.11.0
3.11.0/envs/pytest-3.11.0
3.11.0/envs/qrimg-3.11.0
3.11.0/envs/shiv-3.11.0
3.11.0/envs/speedtest-cli-3.11.0
3.11.0/envs/sphinx-3.11.0
3.11.0/envs/tox-3.11.0
3.11.0/envs/tweet-delete-3.11.0
3.11.0/envs/yamllint-3.11.0
3.11.0/envs/youtube-dl-3.11.0
3.11.1/envs/borg-3.11.1
3.11.1/envs/qontract-3.11.1
3.11.1/envs/requests-3.11.1
3.11.1/envs/titlecase-3.11.1
3.11.1/envs/uptime-kuma-3.11.1
3.11.10/envs/ipython-3.11.10
3.11.10/envs/koku-dev-3.11.10
3.11.10/envs/koku-test
3.11.2/envs/bonfire-3.11.2
3.11.2/envs/testing
3.11.3/envs/ansible-dev-3.11.3
3.11.3/envs/qr-coding-3.11.3
3.11.4/envs/flash
3.11.4/envs/json-linter-3.11.4
3.11.4/envs/youtube-dl-dev
3.11.5/envs/parquet-compactor-3.11.5
3.11.6/envs/ansible-core-3.11.6
3.11.6/envs/pre-commit
3.11.6/envs/pylibssh-dev-3.11.6
3.11.6/envs/tasmota-3.11.6
3.11.7/envs/pipenv-3.11.7
3.11.7/envs/tasmota-3.11.7
3.11.8/envs/cffi-dev-3.11.8
3.11.8/envs/koku-dev-3.11.8
3.11.8/envs/koku-dev-dj4-3.11.8
3.11.9/envs/ipython-3.11.9
3.11.9/envs/koku-dev-3.11.9
3.11.9/envs/nise-populator-3.11.9
3.12.0/envs/ansible-core-3.12.0
3.12.0/envs/cla-dev-3.12.0
3.12.0/envs/ipython-3.12.0
3.12.0/envs/jupyter
3.12.0/envs/koku-metrics-operator-3.12.0
3.12.0/envs/pytorch
3.12.0/envs/requests-3.12.0
3.12.0/envs/rh-pre-commit-3.12.0
3.12.1/envs/ipython-3.12.1
3.12.2/envs/1brc
3.12.2/envs/ansible-core-3.12.2
3.12.2/envs/black
3.12.2/envs/cffi-dev-3.12.2
3.12.2/envs/codecov-cli
3.12.2/envs/dr-content-3.12.2
3.12.2/envs/harlequin
3.12.2/envs/ipython-3.12.2
3.12.2/envs/pip-audit
3.12.2/envs/pygments-3.12.2
3.12.2/envs/pyright
3.12.2/envs/qrcode
3.12.2/envs/ruff
3.12.3/envs/ipython-3.12.3
3.12.5/envs/ipython-3.12.5
3.12.5/envs/shellai
3.12.6/envs/build-definitions
3.12.6/envs/ipython-3.12.6
3.12.6/envs/kflux-rel-data
3.12.7/envs/aoc-2024
3.12.7/envs/ipython-3.12.7
3.12.8/envs/dr-backend-3.12.8
3.12.8/envs/ipython-3.12.8
3.12.8/envs/lifecycle-defs
3.12.8/envs/rlsapi-dev
3.12.8/envs/rlsrag
3.13.0/envs/cffi-3.13.0
3.13.0/envs/cicd-tools
3.13.0/envs/ipython-3.13.0
3.13.0/envs/thefuck
3.13.1/envs/docling
3.13.1/envs/httpie
3.13.1/envs/ipython-3.13.1
3.13.1/envs/llm
3.13.1/envs/locust
3.13.1/envs/poetry
3.13.1/envs/prefix
3.13.1/envs/tox
3.6.15/envs/ipython-3.6.15
3.7.15/envs/ipython-3.7.15
3.7.16/envs/ipython-3.7.16
3.8.14/envs/ansible-dev-3.8.14
3.8.15/envs/ipython-3.8.15
3.8.15/envs/nise-populator-3.8.15
3.8.16/envs/koku-nise-dev-3.8.16
3.8.17/envs/ipython-3.8.17
3.8.18/envs/parquet-compactor-3.8.18
3.8.20/envs/ipython-3.8.20
3.9.14/envs/iqe-3.9.14
3.9.15/envs/ipython-3.9.15
3.9.16/envs/koku-dev-logging-3.9.16
3.9.17/envs/event-sign-3.9.17
3.9.17/envs/ipython-3.9.17
3.9.18/envs/koku-dev-3.9.18
3.9.18/envs/koku-rediscache-debug
3.9.18/envs/parquet-compactor-3.9.18
3.9.19/envs/ipython-3.9.19
3.9.19/envs/koku-dev-3.9.19
ansible-core-3.11.6
ansible-core-3.12.0
ansible-core-3.12.2
ansible-dev-3.11.3
ansible-dev-3.8.14
aoc-2024
argcomplete-3.11.0
asciinema-3.11.0
black
bonfire-3.11.2
borg-3.11.0
borg-3.11.1
build-definitions
cffi-3.13.0
cffi-dev-3.11.8
cffi-dev-3.12.2
cherry_picker-3.10.7
cherry_picker-3.11.0
cicd-tools
cla-dev-3.12.0
codecov-cli
cookiecutter-3.11.0
diceware-3.11.0
docling
dr-backend-3.12.8
dr-content-3.12.2
event-sign-3.9.17
flake8-3.11.0
flash
harlequin
httpie
instruct-lab
ipdb-3.11.0
ipython-3.10.14
ipython-3.10.15
ipython-3.11.10
ipython-3.11.9
ipython-3.12.0
ipython-3.12.1
ipython-3.12.2
ipython-3.12.3
ipython-3.12.5
ipython-3.12.6
ipython-3.12.7
ipython-3.12.8
ipython-3.13.0
ipython-3.13.1
ipython-3.6.15
ipython-3.7.15
ipython-3.7.16
ipython-3.8.15
ipython-3.8.17
ipython-3.8.20
ipython-3.9.15
ipython-3.9.17
ipython-3.9.19
iqe-3.9.14
isort-3.11.0
jello-3.11.0
json-linter-3.11.4
jupyter
kflux-rel-data
koku-dev-3.11.10
koku-dev-3.11.8
koku-dev-3.11.9
koku-dev-3.9.18
koku-dev-3.9.19
koku-dev-dj4-3.11.8
koku-dev-logging-3.9.16
koku-metrics-operator-3.12.0
koku-nise-dev-3.8.16
koku-rediscache-debug
koku-test
lifecycle-defs
llm
locust
mackup-3.11.0
maestral-3.11.0
mitmproxy-3.11.0
mypy-3.11.0
nise-populator-3.11.9
nise-populator-3.8.15
parquet-compactor-3.10.13
parquet-compactor-3.11.5
parquet-compactor-3.8.18
parquet-compactor-3.9.18
pip-audit
pipenv-3.11.7
pipfile2req-3.11.0
poetry
pre-commit
prefix
pur-3.11.0
pygments-3.12.2
pylibssh-dev-3.11.6
pylint-3.11.0
pyls-3.10.9
pyright
pyspy-3.11.0
pytest-3.11.0
pytorch
qontract-3.11.1
qr-coding-3.11.3
qrcode
qrimg-3.11.0
requests-3.11.1
requests-3.12.0
rh-pre-commit-3.12.0
rlsapi-dev
rlsrag
ruff
shellai
shiv-3.11.0
speedtest-cli-3.11.0
sphinx-3.11.0
tasmota-3.11.6
tasmota-3.11.7
testing
thefuck
titlecase-3.11.1
tox
tox-3.11.0
tweet-delete-3.11.0
uptime-kuma-3.11.1
yamllint-3.11.0
youtube-dl-3.11.0
youtube-dl-dev

With the changes in this branch it is 236ms:

> time pyenv virtualenvs --bare > /dev/null 2>&1

________________________________________________________
Executed in  236.02 millis    fish           external
   usr time   36.14 millis    0.31 millis   35.83 millis
   sys time   31.66 millis    3.17 millis   28.48 millis
Output
3.10.13/envs/instruct-lab
3.10.13/envs/parquet-compactor-3.10.13
3.10.14/envs/ipython-3.10.14
3.10.15/envs/ipython-3.10.15
3.10.7/envs/cherry_picker-3.10.7
3.10.9/envs/pyls-3.10.9
3.11.0/envs/argcomplete-3.11.0
3.11.0/envs/asciinema-3.11.0
3.11.0/envs/borg-3.11.0
3.11.0/envs/cherry_picker-3.11.0
3.11.0/envs/cookiecutter-3.11.0
3.11.0/envs/diceware-3.11.0
3.11.0/envs/flake8-3.11.0
3.11.0/envs/ipdb-3.11.0
3.11.0/envs/isort-3.11.0
3.11.0/envs/jello-3.11.0
3.11.0/envs/mackup-3.11.0
3.11.0/envs/maestral-3.11.0
3.11.0/envs/mitmproxy-3.11.0
3.11.0/envs/mypy-3.11.0
3.11.0/envs/pipfile2req-3.11.0
3.11.0/envs/pur-3.11.0
3.11.0/envs/pylint-3.11.0
3.11.0/envs/pyspy-3.11.0
3.11.0/envs/pytest-3.11.0
3.11.0/envs/qrimg-3.11.0
3.11.0/envs/shiv-3.11.0
3.11.0/envs/speedtest-cli-3.11.0
3.11.0/envs/sphinx-3.11.0
3.11.0/envs/tox-3.11.0
3.11.0/envs/tweet-delete-3.11.0
3.11.0/envs/yamllint-3.11.0
3.11.0/envs/youtube-dl-3.11.0
3.11.1/envs/borg-3.11.1
3.11.1/envs/qontract-3.11.1
3.11.1/envs/requests-3.11.1
3.11.1/envs/titlecase-3.11.1
3.11.1/envs/uptime-kuma-3.11.1
3.11.10/envs/ipython-3.11.10
3.11.10/envs/koku-dev-3.11.10
3.11.10/envs/koku-test
3.11.2/envs/bonfire-3.11.2
3.11.2/envs/testing
3.11.3/envs/ansible-dev-3.11.3
3.11.3/envs/qr-coding-3.11.3
3.11.4/envs/flash
3.11.4/envs/json-linter-3.11.4
3.11.4/envs/youtube-dl-dev
3.11.5/envs/parquet-compactor-3.11.5
3.11.6/envs/ansible-core-3.11.6
3.11.6/envs/pre-commit
3.11.6/envs/pylibssh-dev-3.11.6
3.11.6/envs/tasmota-3.11.6
3.11.7/envs/pipenv-3.11.7
3.11.7/envs/tasmota-3.11.7
3.11.8/envs/cffi-dev-3.11.8
3.11.8/envs/koku-dev-3.11.8
3.11.8/envs/koku-dev-dj4-3.11.8
3.11.9/envs/ipython-3.11.9
3.11.9/envs/koku-dev-3.11.9
3.11.9/envs/nise-populator-3.11.9
3.12.0/envs/ansible-core-3.12.0
3.12.0/envs/cla-dev-3.12.0
3.12.0/envs/ipython-3.12.0
3.12.0/envs/jupyter
3.12.0/envs/koku-metrics-operator-3.12.0
3.12.0/envs/pytorch
3.12.0/envs/requests-3.12.0
3.12.0/envs/rh-pre-commit-3.12.0
3.12.1/envs/ipython-3.12.1
3.12.2/envs/1brc
3.12.2/envs/ansible-core-3.12.2
3.12.2/envs/black
3.12.2/envs/cffi-dev-3.12.2
3.12.2/envs/codecov-cli
3.12.2/envs/dr-content-3.12.2
3.12.2/envs/harlequin
3.12.2/envs/ipython-3.12.2
3.12.2/envs/pip-audit
3.12.2/envs/pygments-3.12.2
3.12.2/envs/pyright
3.12.2/envs/qrcode
3.12.2/envs/ruff
3.12.3/envs/ipython-3.12.3
3.12.5/envs/ipython-3.12.5
3.12.5/envs/shellai
3.12.6/envs/build-definitions
3.12.6/envs/ipython-3.12.6
3.12.6/envs/kflux-rel-data
3.12.7/envs/aoc-2024
3.12.7/envs/ipython-3.12.7
3.12.8/envs/dr-backend-3.12.8
3.12.8/envs/ipython-3.12.8
3.12.8/envs/lifecycle-defs
3.12.8/envs/rlsapi-dev
3.12.8/envs/rlsrag
3.13.0/envs/cffi-3.13.0
3.13.0/envs/cicd-tools
3.13.0/envs/ipython-3.13.0
3.13.0/envs/thefuck
3.13.1/envs/docling
3.13.1/envs/httpie
3.13.1/envs/ipython-3.13.1
3.13.1/envs/llm
3.13.1/envs/locust
3.13.1/envs/poetry
3.13.1/envs/prefix
3.13.1/envs/tox
3.6.15/envs/ipython-3.6.15
3.7.15/envs/ipython-3.7.15
3.7.16/envs/ipython-3.7.16
3.8.14/envs/ansible-dev-3.8.14
3.8.15/envs/ipython-3.8.15
3.8.15/envs/nise-populator-3.8.15
3.8.16/envs/koku-nise-dev-3.8.16
3.8.17/envs/ipython-3.8.17
3.8.18/envs/parquet-compactor-3.8.18
3.8.20/envs/ipython-3.8.20
3.9.14/envs/iqe-3.9.14
3.9.15/envs/ipython-3.9.15
3.9.16/envs/koku-dev-logging-3.9.16
3.9.17/envs/event-sign-3.9.17
3.9.17/envs/ipython-3.9.17
3.9.18/envs/koku-dev-3.9.18
3.9.18/envs/koku-rediscache-debug
3.9.18/envs/parquet-compactor-3.9.18
3.9.19/envs/ipython-3.9.19
3.9.19/envs/koku-dev-3.9.19
1brc
ansible-core-3.11.6
ansible-core-3.12.0
ansible-core-3.12.2
ansible-dev-3.11.3
ansible-dev-3.8.14
aoc-2024
argcomplete-3.11.0
asciinema-3.11.0
black
bonfire-3.11.2
borg-3.11.0
borg-3.11.1
build-definitions
cffi-3.13.0
cffi-dev-3.11.8
cffi-dev-3.12.2
cherry_picker-3.10.7
cherry_picker-3.11.0
cicd-tools
cla-dev-3.12.0
codecov-cli
cookiecutter-3.11.0
diceware-3.11.0
docling
dr-backend-3.12.8
dr-content-3.12.2
event-sign-3.9.17
flake8-3.11.0
flash
harlequin
httpie
instruct-lab
ipdb-3.11.0
ipython-3.10.14
ipython-3.10.15
ipython-3.11.10
ipython-3.11.9
ipython-3.12.0
ipython-3.12.1
ipython-3.12.2
ipython-3.12.3
ipython-3.12.5
ipython-3.12.6
ipython-3.12.7
ipython-3.12.8
ipython-3.13.0
ipython-3.13.1
ipython-3.6.15
ipython-3.7.15
ipython-3.7.16
ipython-3.8.15
ipython-3.8.17
ipython-3.8.20
ipython-3.9.15
ipython-3.9.17
ipython-3.9.19
iqe-3.9.14
isort-3.11.0
jello-3.11.0
json-linter-3.11.4
jupyter
kflux-rel-data
koku-dev-3.11.10
koku-dev-3.11.8
koku-dev-3.11.9
koku-dev-3.9.18
koku-dev-3.9.19
koku-dev-dj4-3.11.8
koku-dev-logging-3.9.16
koku-metrics-operator-3.12.0
koku-nise-dev-3.8.16
koku-rediscache-debug
koku-test
lifecycle-defs
llm
locust
mackup-3.11.0
maestral-3.11.0
mitmproxy-3.11.0
mypy-3.11.0
nise-populator-3.11.9
nise-populator-3.8.15
parquet-compactor-3.10.13
parquet-compactor-3.11.5
parquet-compactor-3.8.18
parquet-compactor-3.9.18
pip-audit
pipenv-3.11.7
pipfile2req-3.11.0
poetry
pre-commit
prefix
pur-3.11.0
pygments-3.12.2
pylibssh-dev-3.11.6
pylint-3.11.0
pyls-3.10.9
pyright
pyspy-3.11.0
pytest-3.11.0
pytorch
qontract-3.11.1
qr-coding-3.11.3
qrcode
qrimg-3.11.0
requests-3.11.1
requests-3.12.0
rh-pre-commit-3.12.0
rlsapi-dev
rlsrag
ruff
shellai
shiv-3.11.0
speedtest-cli-3.11.0
sphinx-3.11.0
tasmota-3.11.6
tasmota-3.11.7
testing
thefuck
titlecase-3.11.1
tox
tox-3.11.0
tweet-delete-3.11.0
uptime-kuma-3.11.1
yamllint-3.11.0
youtube-dl-3.11.0
youtube-dl-dev

Output formatting changes

This PR also includes changes to the output format to make it more consistent with pyenv versions.

pyenv versions output
  3.10.13/envs/instruct-lab
  3.10.13/envs/parquet-compactor-3.10.13
  3.10.14/envs/ipython-3.10.14
  3.10.15/envs/ipython-3.10.15
  3.10.7/envs/cherry_picker-3.10.7
  3.10.9/envs/pyls-3.10.9
  3.11.0/envs/argcomplete-3.11.0
  3.11.0/envs/asciinema-3.11.0
  3.11.0/envs/borg-3.11.0
  3.11.0/envs/cherry_picker-3.11.0
  3.11.0/envs/cookiecutter-3.11.0
  3.11.0/envs/diceware-3.11.0
  3.11.0/envs/flake8-3.11.0
  3.11.0/envs/ipdb-3.11.0
  3.11.0/envs/isort-3.11.0
  3.11.0/envs/jello-3.11.0
  3.11.0/envs/mackup-3.11.0
  3.11.0/envs/maestral-3.11.0
  3.11.0/envs/mitmproxy-3.11.0
  3.11.0/envs/mypy-3.11.0
  3.11.0/envs/pipfile2req-3.11.0
  3.11.0/envs/pur-3.11.0
  3.11.0/envs/pylint-3.11.0
  3.11.0/envs/pyspy-3.11.0
  3.11.0/envs/pytest-3.11.0
  3.11.0/envs/qrimg-3.11.0
  3.11.0/envs/shiv-3.11.0
  3.11.0/envs/speedtest-cli-3.11.0
  3.11.0/envs/sphinx-3.11.0
  3.11.0/envs/tox-3.11.0
  3.11.0/envs/tweet-delete-3.11.0
  3.11.0/envs/yamllint-3.11.0
  3.11.0/envs/youtube-dl-3.11.0
  3.11.1/envs/borg-3.11.1
  3.11.1/envs/qontract-3.11.1
  3.11.1/envs/requests-3.11.1
  3.11.1/envs/titlecase-3.11.1
  3.11.1/envs/uptime-kuma-3.11.1
  3.11.10/envs/ipython-3.11.10
  3.11.10/envs/koku-dev-3.11.10
  3.11.10/envs/koku-test
  3.11.2/envs/bonfire-3.11.2
  3.11.2/envs/testing
  3.11.3/envs/ansible-dev-3.11.3
  3.11.3/envs/qr-coding-3.11.3
  3.11.4/envs/flash
  3.11.4/envs/json-linter-3.11.4
  3.11.4/envs/youtube-dl-dev
  3.11.5/envs/parquet-compactor-3.11.5
  3.11.6/envs/ansible-core-3.11.6
  3.11.6/envs/pre-commit
  3.11.6/envs/pylibssh-dev-3.11.6
  3.11.6/envs/tasmota-3.11.6
  3.11.7/envs/pipenv-3.11.7
  3.11.7/envs/tasmota-3.11.7
  3.11.8/envs/cffi-dev-3.11.8
  3.11.8/envs/koku-dev-3.11.8
  3.11.8/envs/koku-dev-dj4-3.11.8
  3.11.9/envs/ipython-3.11.9
  3.11.9/envs/koku-dev-3.11.9
  3.11.9/envs/nise-populator-3.11.9
  3.12.0/envs/ansible-core-3.12.0
  3.12.0/envs/cla-dev-3.12.0
  3.12.0/envs/ipython-3.12.0
  3.12.0/envs/jupyter
  3.12.0/envs/koku-metrics-operator-3.12.0
  3.12.0/envs/pytorch
  3.12.0/envs/requests-3.12.0
  3.12.0/envs/rh-pre-commit-3.12.0
  3.12.1/envs/ipython-3.12.1
  3.12.2/envs/1brc
  3.12.2/envs/ansible-core-3.12.2
  3.12.2/envs/black
  3.12.2/envs/cffi-dev-3.12.2
  3.12.2/envs/codecov-cli
  3.12.2/envs/dr-content-3.12.2
  3.12.2/envs/harlequin
  3.12.2/envs/ipython-3.12.2
  3.12.2/envs/pip-audit
  3.12.2/envs/pygments-3.12.2
  3.12.2/envs/pyright
  3.12.2/envs/qrcode
  3.12.2/envs/ruff
  3.12.3/envs/ipython-3.12.3
  3.12.5/envs/ipython-3.12.5
  3.12.5/envs/shellai
  3.12.6/envs/build-definitions
  3.12.6/envs/ipython-3.12.6
  3.12.6/envs/kflux-rel-data
  3.12.7/envs/aoc-2024
  3.12.7/envs/ipython-3.12.7
  3.12.8/envs/dr-backend-3.12.8
  3.12.8/envs/ipython-3.12.8
  3.12.8/envs/lifecycle-defs
  3.12.8/envs/rlsapi-dev
  3.12.8/envs/rlsrag
  3.13.0/envs/cffi-3.13.0
  3.13.0/envs/cicd-tools
  3.13.0/envs/ipython-3.13.0
  3.13.0/envs/thefuck
  3.13.1/envs/docling
  3.13.1/envs/httpie
  3.13.1/envs/ipython-3.13.1
  3.13.1/envs/llm
  3.13.1/envs/locust
  3.13.1/envs/poetry
  3.13.1/envs/prefix
  3.13.1/envs/tox
  3.6.15/envs/ipython-3.6.15
  3.7.15/envs/ipython-3.7.15
  3.7.16/envs/ipython-3.7.16
  3.8.14/envs/ansible-dev-3.8.14
  3.8.15/envs/ipython-3.8.15
  3.8.15/envs/nise-populator-3.8.15
  3.8.16/envs/koku-nise-dev-3.8.16
  3.8.17/envs/ipython-3.8.17
  3.8.18/envs/parquet-compactor-3.8.18
  3.8.20/envs/ipython-3.8.20
  3.9.14/envs/iqe-3.9.14
  3.9.15/envs/ipython-3.9.15
  3.9.16/envs/koku-dev-logging-3.9.16
  3.9.17/envs/event-sign-3.9.17
  3.9.17/envs/ipython-3.9.17
  3.9.18/envs/koku-dev-3.9.18
  3.9.18/envs/koku-rediscache-debug
  3.9.18/envs/parquet-compactor-3.9.18
  3.9.19/envs/ipython-3.9.19
  3.9.19/envs/koku-dev-3.9.19
  1brc --> /Users/sdoran/.pyenv/versions/3.12.2/envs/1brc
  ansible-core-3.11.6 --> /Users/sdoran/.pyenv/versions/3.11.6/envs/ansible-core-3.11.6
  ansible-core-3.12.0 --> /Users/sdoran/.pyenv/versions/3.12.0/envs/ansible-core-3.12.0
  ansible-core-3.12.2 --> /Users/sdoran/.pyenv/versions/3.12.2/envs/ansible-core-3.12.2
  ansible-dev-3.11.3 --> /Users/sdoran/.pyenv/versions/3.11.3/envs/ansible-dev-3.11.3
  ansible-dev-3.8.14 --> /Users/sdoran/.pyenv/versions/3.8.14/envs/ansible-dev-3.8.14
  aoc-2024 --> /Users/sdoran/.pyenv/versions/3.12.7/envs/aoc-2024
  argcomplete-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/argcomplete-3.11.0
  asciinema-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/asciinema-3.11.0
  black --> /Users/sdoran/.pyenv/versions/3.12.2/envs/black
  bonfire-3.11.2 --> /Users/sdoran/.pyenv/versions/3.11.2/envs/bonfire-3.11.2
  borg-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/borg-3.11.0
  borg-3.11.1 --> /Users/sdoran/.pyenv/versions/3.11.1/envs/borg-3.11.1
  build-definitions --> /Users/sdoran/.pyenv/versions/3.12.6/envs/build-definitions
  cffi-3.13.0 --> /Users/sdoran/.pyenv/versions/3.13.0/envs/cffi-3.13.0
  cffi-dev-3.11.8 --> /Users/sdoran/.pyenv/versions/3.11.8/envs/cffi-dev-3.11.8
  cffi-dev-3.12.2 --> /Users/sdoran/.pyenv/versions/3.12.2/envs/cffi-dev-3.12.2
  cherry_picker-3.10.7 --> /Users/sdoran/.pyenv/versions/3.10.7/envs/cherry_picker-3.10.7
  cherry_picker-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/cherry_picker-3.11.0
  cicd-tools --> /Users/sdoran/.pyenv/versions/3.13.0/envs/cicd-tools
  cla-dev-3.12.0 --> /Users/sdoran/.pyenv/versions/3.12.0/envs/cla-dev-3.12.0
  codecov-cli --> /Users/sdoran/.pyenv/versions/3.12.2/envs/codecov-cli
  cookiecutter-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/cookiecutter-3.11.0
  diceware-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/diceware-3.11.0
  docling --> /Users/sdoran/.pyenv/versions/3.13.1/envs/docling
  dr-backend-3.12.8 --> /Users/sdoran/.pyenv/versions/3.12.8/envs/dr-backend-3.12.8
  dr-content-3.12.2 --> /Users/sdoran/.pyenv/versions/3.12.2/envs/dr-content-3.12.2
  event-sign-3.9.17 --> /Users/sdoran/.pyenv/versions/3.9.17/envs/event-sign-3.9.17
  flake8-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/flake8-3.11.0
  flash --> /Users/sdoran/.pyenv/versions/3.11.4/envs/flash
  harlequin --> /Users/sdoran/.pyenv/versions/3.12.2/envs/harlequin
  httpie --> /Users/sdoran/.pyenv/versions/3.13.1/envs/httpie
  instruct-lab --> /Users/sdoran/.pyenv/versions/3.10.13/envs/instruct-lab
  ipdb-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/ipdb-3.11.0
  ipython-3.10.14 --> /Users/sdoran/.pyenv/versions/3.10.14/envs/ipython-3.10.14
  ipython-3.10.15 --> /Users/sdoran/.pyenv/versions/3.10.15/envs/ipython-3.10.15
  ipython-3.11.10 --> /Users/sdoran/.pyenv/versions/3.11.10/envs/ipython-3.11.10
  ipython-3.11.9 --> /Users/sdoran/.pyenv/versions/3.11.9/envs/ipython-3.11.9
  ipython-3.12.0 --> /Users/sdoran/.pyenv/versions/3.12.0/envs/ipython-3.12.0
  ipython-3.12.1 --> /Users/sdoran/.pyenv/versions/3.12.1/envs/ipython-3.12.1
  ipython-3.12.2 --> /Users/sdoran/.pyenv/versions/3.12.2/envs/ipython-3.12.2
  ipython-3.12.3 --> /Users/sdoran/.pyenv/versions/3.12.3/envs/ipython-3.12.3
  ipython-3.12.5 --> /Users/sdoran/.pyenv/versions/3.12.5/envs/ipython-3.12.5
  ipython-3.12.6 --> /Users/sdoran/.pyenv/versions/3.12.6/envs/ipython-3.12.6
  ipython-3.12.7 --> /Users/sdoran/.pyenv/versions/3.12.7/envs/ipython-3.12.7
  ipython-3.12.8 --> /Users/sdoran/.pyenv/versions/3.12.8/envs/ipython-3.12.8
  ipython-3.13.0 --> /Users/sdoran/.pyenv/versions/3.13.0/envs/ipython-3.13.0
  ipython-3.13.1 --> /Users/sdoran/.pyenv/versions/3.13.1/envs/ipython-3.13.1
  ipython-3.6.15 --> /Users/sdoran/.pyenv/versions/3.6.15/envs/ipython-3.6.15
  ipython-3.7.15 --> /Users/sdoran/.pyenv/versions/3.7.15/envs/ipython-3.7.15
  ipython-3.7.16 --> /Users/sdoran/.pyenv/versions/3.7.16/envs/ipython-3.7.16
  ipython-3.8.15 --> /Users/sdoran/.pyenv/versions/3.8.15/envs/ipython-3.8.15
  ipython-3.8.17 --> /Users/sdoran/.pyenv/versions/3.8.17/envs/ipython-3.8.17
  ipython-3.8.20 --> /Users/sdoran/.pyenv/versions/3.8.20/envs/ipython-3.8.20
  ipython-3.9.15 --> /Users/sdoran/.pyenv/versions/3.9.15/envs/ipython-3.9.15
  ipython-3.9.17 --> /Users/sdoran/.pyenv/versions/3.9.17/envs/ipython-3.9.17
  ipython-3.9.19 --> /Users/sdoran/.pyenv/versions/3.9.19/envs/ipython-3.9.19
  iqe-3.9.14 --> /Users/sdoran/.pyenv/versions/3.9.14/envs/iqe-3.9.14
  isort-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/isort-3.11.0
  jello-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/jello-3.11.0
  json-linter-3.11.4 --> /Users/sdoran/.pyenv/versions/3.11.4/envs/json-linter-3.11.4
  jupyter --> /Users/sdoran/.pyenv/versions/3.12.0/envs/jupyter
  kflux-rel-data --> /Users/sdoran/.pyenv/versions/3.12.6/envs/kflux-rel-data
  koku-dev-3.11.10 --> /Users/sdoran/.pyenv/versions/3.11.10/envs/koku-dev-3.11.10
  koku-dev-3.11.8 --> /Users/sdoran/.pyenv/versions/3.11.8/envs/koku-dev-3.11.8
  koku-dev-3.11.9 --> /Users/sdoran/.pyenv/versions/3.11.9/envs/koku-dev-3.11.9
  koku-dev-3.9.18 --> /Users/sdoran/.pyenv/versions/3.9.18/envs/koku-dev-3.9.18
  koku-dev-3.9.19 --> /Users/sdoran/.pyenv/versions/3.9.19/envs/koku-dev-3.9.19
  koku-dev-dj4-3.11.8 --> /Users/sdoran/.pyenv/versions/3.11.8/envs/koku-dev-dj4-3.11.8
  koku-dev-logging-3.9.16 --> /Users/sdoran/.pyenv/versions/3.9.16/envs/koku-dev-logging-3.9.16
  koku-metrics-operator-3.12.0 --> /Users/sdoran/.pyenv/versions/3.12.0/envs/koku-metrics-operator-3.12.0
  koku-nise-dev-3.8.16 --> /Users/sdoran/.pyenv/versions/3.8.16/envs/koku-nise-dev-3.8.16
  koku-rediscache-debug --> /Users/sdoran/.pyenv/versions/3.9.18/envs/koku-rediscache-debug
  koku-test --> /Users/sdoran/.pyenv/versions/3.11.10/envs/koku-test
  lifecycle-defs --> /Users/sdoran/.pyenv/versions/3.12.8/envs/lifecycle-defs
  llm --> /Users/sdoran/.pyenv/versions/3.13.1/envs/llm
  locust --> /Users/sdoran/.pyenv/versions/3.13.1/envs/locust
  mackup-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/mackup-3.11.0
  maestral-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/maestral-3.11.0
  mitmproxy-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/mitmproxy-3.11.0
  mypy-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/mypy-3.11.0
  nise-populator-3.11.9 --> /Users/sdoran/.pyenv/versions/3.11.9/envs/nise-populator-3.11.9
  nise-populator-3.8.15 --> /Users/sdoran/.pyenv/versions/3.8.15/envs/nise-populator-3.8.15
  parquet-compactor-3.10.13 --> /Users/sdoran/.pyenv/versions/3.10.13/envs/parquet-compactor-3.10.13
  parquet-compactor-3.11.5 --> /Users/sdoran/.pyenv/versions/3.11.5/envs/parquet-compactor-3.11.5
  parquet-compactor-3.8.18 --> /Users/sdoran/.pyenv/versions/3.8.18/envs/parquet-compactor-3.8.18
  parquet-compactor-3.9.18 --> /Users/sdoran/.pyenv/versions/3.9.18/envs/parquet-compactor-3.9.18
  pip-audit --> /Users/sdoran/.pyenv/versions/3.12.2/envs/pip-audit
  pipenv-3.11.7 --> /Users/sdoran/.pyenv/versions/3.11.7/envs/pipenv-3.11.7
  pipfile2req-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/pipfile2req-3.11.0
  poetry --> /Users/sdoran/.pyenv/versions/3.13.1/envs/poetry
  pre-commit --> /Users/sdoran/.pyenv/versions/3.11.6/envs/pre-commit
  prefix --> /Users/sdoran/.pyenv/versions/3.13.1/envs/prefix
  pur-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/pur-3.11.0
  pygments-3.12.2 --> /Users/sdoran/.pyenv/versions/3.12.2/envs/pygments-3.12.2
  pylibssh-dev-3.11.6 --> /Users/sdoran/.pyenv/versions/3.11.6/envs/pylibssh-dev-3.11.6
  pylint-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/pylint-3.11.0
  pyls-3.10.9 --> /Users/sdoran/.pyenv/versions/3.10.9/envs/pyls-3.10.9
  pyright --> /Users/sdoran/.pyenv/versions/3.12.2/envs/pyright
  pyspy-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/pyspy-3.11.0
  pytest-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/pytest-3.11.0
  pytorch --> /Users/sdoran/.pyenv/versions/3.12.0/envs/pytorch
  qontract-3.11.1 --> /Users/sdoran/.pyenv/versions/3.11.1/envs/qontract-3.11.1
  qr-coding-3.11.3 --> /Users/sdoran/.pyenv/versions/3.11.3/envs/qr-coding-3.11.3
  qrcode --> /Users/sdoran/.pyenv/versions/3.12.2/envs/qrcode
  qrimg-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/qrimg-3.11.0
  requests-3.11.1 --> /Users/sdoran/.pyenv/versions/3.11.1/envs/requests-3.11.1
  requests-3.12.0 --> /Users/sdoran/.pyenv/versions/3.12.0/envs/requests-3.12.0
  rh-pre-commit-3.12.0 --> /Users/sdoran/.pyenv/versions/3.12.0/envs/rh-pre-commit-3.12.0
  rlsapi-dev --> /Users/sdoran/.pyenv/versions/3.12.8/envs/rlsapi-dev
  rlsrag --> /Users/sdoran/.pyenv/versions/3.12.8/envs/rlsrag
  ruff --> /Users/sdoran/.pyenv/versions/3.12.2/envs/ruff
  shellai --> /Users/sdoran/.pyenv/versions/3.12.5/envs/shellai
  shiv-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/shiv-3.11.0
  speedtest-cli-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/speedtest-cli-3.11.0
  sphinx-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/sphinx-3.11.0
  tasmota-3.11.6 --> /Users/sdoran/.pyenv/versions/3.11.6/envs/tasmota-3.11.6
  tasmota-3.11.7 --> /Users/sdoran/.pyenv/versions/3.11.7/envs/tasmota-3.11.7
  testing --> /Users/sdoran/.pyenv/versions/3.11.2/envs/testing
  thefuck --> /Users/sdoran/.pyenv/versions/3.13.0/envs/thefuck
  titlecase-3.11.1 --> /Users/sdoran/.pyenv/versions/3.11.1/envs/titlecase-3.11.1
  tox --> /Users/sdoran/.pyenv/versions/3.13.1/envs/tox
  tox-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/tox-3.11.0
  tweet-delete-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/tweet-delete-3.11.0
  uptime-kuma-3.11.1 --> /Users/sdoran/.pyenv/versions/3.11.1/envs/uptime-kuma-3.11.1
  yamllint-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/yamllint-3.11.0
  youtube-dl-3.11.0 --> /Users/sdoran/.pyenv/versions/3.11.0/envs/youtube-dl-3.11.0
  youtube-dl-dev --> /Users/sdoran/.pyenv/versions/3.11.4/envs/youtube-dl-dev

There is now an --only-aliases flag. I found this useful to make the shell completions less verbose.

The completions for pyenv virtualenv now omit aliases and envs. I believe only installed Python versions should be suggested instead of current virtual environments, which are aliases.

Use the code from pyenv-versions for efficiency and consistent output.

The main performance problem was in the call to pyenv-virtualenv-prefix,
which called pyenv-prefix, which then enumerated every virtual environment.
This was done inside a loop, compounding the problem.

Simply the virtual environment listing so that it does not have to call
pyenv-virtualenv-prefix anymore.
This is useful for listing the “frinedly” virtualenv names instead of
the short path which includes the Python version.
…vironments

Having the current virtual environments listed as options in the competion
is noisy since only bare Python versions, such as 3.11.1, make sense as
suggested completions for `pyenv virtualenv [version]`.
This makes the suggested completetions cleaner.
@samdoran
Copy link
Author

I could use some help getting the tests correct. I made a few changes but I don't understand why the unstub commands were failing or how to get a virtual env to show up as "activated" in the test environment.

@pyenv pyenv deleted a comment from samdoran Feb 13, 2025
@ChristianFredrikJohnsen

Seems like only two tests are failing 😄

I just randomly checked into virtualenv. I recently did some perf improvements on the main pyenv repo, and I found myself spending more work fixing the tests (and understanding bats, etc.) than actually improving the source code.
In the pyenv repo, I found that some parts of the code were just written to enable tests to pass, and had no actual value beyond that.

I am not sure if this applies to your situation as well, haven't looked much into it. The main idea I have is:

The code may be perfectly fine, but the tests can be a mess!

@samdoran
Copy link
Author

The tests do need some adjusting since I've changed the output a bit. I'm just having a hard time figuring out what exactly stub and unstub do as well as how to "activate" a venv in the test environment. Testing is always the hard part.

@ChristianFredrikJohnsen

Hehe, and the test file hasn't been touched in 10 years 😆
Same thing I ran into in the pyenv project. Probably only the guy who initially created this stuff knows.

I did not encounter stub and unstub when I did testing in pyenv, and there was no activate there as well (since no virtualenvs of course). Yeah, I don't have any quick answers 💀 It's a pain 🥲

@samdoran
Copy link
Author

The code itself that was the source of the performance issue is 10-12 years old. Not that old code is bad, but there were some inefficiencies in there.

@ChristianFredrikJohnsen

No it's not that the old code is bad. It was probably good at the time it was written. It's more of a problem that the code has design principles which made sense back then, but fast forward 10 years and it's not as intuitive anymore.

And if you're unlucky, you're facing tests which were quick-fix set up 10 years ago, and suddenly you need to fix the problem of ...
Not necessarily the problem of any one person either, it's just that the entire structure doesn't feel intuitive.

It's a challenge for sure 😄

@@ -34,10 +34,11 @@ for arg; do
case "$arg" in
--complete )
echo --bare
echo --skip-aliases
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

both options remain

echo "${miss_prefix}${1}${print_origin+$2}"
version_repr="$version"
fi
if [[ ${BASH_VERSINFO[0]} -ge 4 && ${current_versions["$1"]} ]]; then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Version check inconsistent with other cases. Not a malfunction but a code smell. Is the difference significant?

Comment on lines +51 to +76
if ! enable -f "${BASH_SOURCE%/*}"/pyenv-realpath.dylib realpath 2>/dev/null; then
if [ -n "$PYENV_NATIVE_EXT" ]; then
echo "pyenv: failed to load \`realpath' builtin" >&2
exit 1
fi

READLINK=$(type -P readlink)
if [ -z "$READLINK" ]; then
echo "pyenv: cannot find readlink - are you missing GNU coreutils?" >&2
exit 1
fi

resolve_link() {
$READLINK "$1"
}

realpath() {
local path="$1"
local name

# Use a subshell to avoid changing the current path
(
while [ -n "$path" ]; do
name="${path##*/}"
[ "$name" = "$path" ] || cd "${path%/*}"
path="$(resolve_link "$name" || true)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already source pyenv-virtualenv-realpath. Does it not work or smth?
The new code doesn't seem to even be using realpath -- if that's correct, neither is needed.

Comment on lines +168 to +182
if [ -z "$only_aliases" ]; then
for env_path in "${venv_dir_entries[@]}"; do
if [ -d "${env_path}" ]; then
print_version "${env_path#"${PYENV_ROOT}"/versions/}" "${env_path}"
fi
virtualenv_prefix="$(pyenv-virtualenv-prefix "${path##*/}" 2>/dev/null || true)"
if [ -d "${virtualenv_prefix}" ]; then
print_version "${path##*/}" " (created from ${virtualenv_prefix})"
done
fi

if [ -z "$skip_aliases" ]; then
for env_path in "${version_dir_entries[@]}"; do
if [ -d "${env_path}" ] && [ -L "${env_path}" ]; then
print_version "${env_path#"${PYENV_ROOT}"/versions/}" "${env_path}"
fi
for venv_path in "${path}/envs/"*; do
venv="${path##*/}/envs/${venv_path##*/}"
virtualenv_prefix="$(pyenv-virtualenv-prefix "${venv}" 2>/dev/null || true)"
if [ -d "${virtualenv_prefix}" ]; then
print_version "${venv}" " (created from ${virtualenv_prefix})"
fi
done
fi
done
done
fi
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens with conda installations? They are currently listed, now they seem to stop being so.
Not sure why they are listed and if that's intended. Technically, each one contains a "base" environment -- but the same could be said about any other Python installation.

Comment on lines +9 to +10
ln -s "venv27" "${PYENV_ROOT}/versions/venv27"
ln -s "venv33" "${PYENV_ROOT}/versions/venv33"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICS the links are created in the current directory. That doesn't seem correct.
There's a dedicated function to create aliases.

Comment on lines +48 to +49
2.7.6/envs/venv27
* 3.3.3/envs/venv33
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Diagnosed this failure. The logic does not equate "xxx" with "yyy/envs/xxx". If you set current version to "venv33", the alias will be the highlighted entry, not the full name.

To diagnose stuff in tests, I set PS4 to the long value from the launcher and run the command with PYENV_DEBUG=1. Then make sure there's a command later that prints its output in some form (in this case, assert_output failure handling logic).

Comment on lines +41 to +42
stub pyenv-virtualenv-prefix "venv27 : echo \"${PYENV_ROOT}/versions/2.7.6\""
stub pyenv-virtualenv-prefix "venv33 : echo \"${PYENV_ROOT}/versions/3.3.3\""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this change improves anything. As a rule of thumb, one should not change test cases unless you've changed the behavior in them -- to avoid accidentally losing test cover.

OUT

unstub pyenv-version-name
unstub pyenv-virtualenv-prefix
# unstub pyenv-version-name
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unstub checcks if the specific stubbed executable was called exactly according to the sequence set up with stub calls. If not, it fails and prints the plan and the fact.
The implementation is in test_helper.bash and the stubs/stub script which the former calls.

@@ -17,7 +17,7 @@ set -e
# Provide pyenv completions
if [ "$1" = "--complete" ]; then
echo --unset
exec pyenv-virtualenvs --bare
exec pyenv-virtualenvs --bare --only-aliases
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a design change -- so this should be discussed separately. Envs are supposed to be accessible under both full name and alias. I'm not sure why that is; aliases are internally called "compat", indicating that they were added for compatibility with... something.

@@ -51,7 +51,7 @@ while [ $# -gt 0 ]; do
"--complete" )
# Provide pyenv completions
echo --unset
exec pyenv-virtualenvs --bare
exec pyenv-virtualenvs --bare --only-aliases
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

@samdoran
Copy link
Author

Thank you for the feedback @native-api. I'll address this later in the week.

@samdoran
Copy link
Author

I had a crazy week and a full weekend away from home. I will work on this during the week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants