From 03cabd88e938fd23c82c32a0889e3aa52f1d8d5c Mon Sep 17 00:00:00 2001 From: Ivan Pozdeev Date: Wed, 2 Jun 2021 12:43:46 +0300 Subject: [PATCH 1/6] Highlight MacOS note about restart --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 214fe045..78f368af 100644 --- a/README.md +++ b/README.md @@ -341,7 +341,7 @@ easy to fork and contribute any changes back upstream. 4. **Restart your login session for the changes to take effect.** E.g. if you're in a GUI session, you need to fully log out and log back in. - In MacOS, restarting terminal windows is enough (because MacOS runs shells + **In MacOS,** restarting terminal windows is enough (because MacOS runs shells in them as login shells by default). 5. [**Install Python build dependencies**](https://github.com/pyenv/pyenv/wiki#suggested-build-environment) before attempting to install a new Python version. From 8cce6e8dd297f4f5c5d9784fc5dca082bd61ba7c Mon Sep 17 00:00:00 2001 From: Ivan Pozdeev Date: Tue, 8 Jun 2021 17:23:08 +0300 Subject: [PATCH 2/6] Add notes when to use the 2nd shell step --- README.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 78f368af..eb5e2dd5 100644 --- a/README.md +++ b/README.md @@ -206,8 +206,9 @@ easy to fork and contribute any changes back upstream. 2. **Configure your shell's environment for Pyenv** - **Note:** The below instructions for specific shells are designed for common shell setups. - If you have an uncommon setup and they don't work for you, + **Note:** The below instructions for specific shells are designed for common shell setups; + they also install shell functions into interactive shells only. + If you have an uncommon setup and/or special needs and they don't work for you, use the guidance text and the [Advanced Configuration](#advanced-configuration) section below to figure out what you need to do in your specific case. @@ -303,10 +304,15 @@ easy to fork and contribute any changes back upstream. **Proxy note**: If you use a proxy, export `http_proxy` and `https_proxy`, too. - 2. **Add `pyenv` into your shell** by running the output of `pyenv init -` - to enable autocompletion and all subcommands. - - This command needs to run at startup of any interactive shell instance. + 2. **Add `pyenv` into your shell as a shell function** by running the output of `pyenv init -` + to enable autocompletion and subcommands that require `pyenv` to be a shell function. + + The subcommands enabled by this step are those that make changes to the current shell environment. + In Pyenv, that's only `pyenv shell`; another example is `pyenv activate` from the + [Pyenv-Virtualenv](https://github.com/pyenv/pyenv-virtualenv) plugin. + + This step is optional. Run it whenever you need the above functions -- + typically at startup of any interactive shell. In an interactive login shell, it needs to run _after_ the commands from the previous step. From 6c74b616a5970be0e42c4eacfd3810eb6aca4a9d Mon Sep 17 00:00:00 2001 From: Ivan Pozdeev Date: Tue, 8 Jun 2021 17:31:54 +0300 Subject: [PATCH 3/6] Windows note as a separate section --- README.md | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index eb5e2dd5..7d55afac 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,10 @@ This project was forked from [rbenv](https://github.com/rbenv/rbenv) and * [Choosing the Python Version](#choosing-the-python-version) * [Locating the Python Installation](#locating-the-python-installation) * **[Installation](#installation)** + * [Prerequisites](#prerequisites) + * [Homebrew in macOS](#homebrew-in-macos) + * [Windows](#windows) + * [Automatic installer](#automatic-installer) * [Basic GitHub Checkout](#basic-github-checkout) * [Upgrading](#upgrading) * [Homebrew on macOS](#homebrew-on-macos) @@ -168,11 +172,11 @@ We'd recommend to install pyenv-virtualenv as well if you have some plan to play ## Installation -### Prerequisites: +### Prerequisites For pyenv to install python correctly you should [**install the Python build dependencies**](https://github.com/pyenv/pyenv/wiki#suggested-build-environment). -### Homebrew on macOS +### Homebrew in macOS 1. Consider installing with [Homebrew](https://brew.sh): ```sh @@ -181,9 +185,20 @@ For pyenv to install python correctly you should [**install the Python build dep ``` 2. Then follow the rest of the post-installation steps under [Basic GitHub Checkout](https://github.com/pyenv/pyenv#basic-github-checkout), starting with #2 ("Configure your shell's environment for Pyenv"). -If you're on Windows, consider using @kirankotari's [`pyenv-win`](https://github.com/pyenv-win/pyenv-win) fork. (Pyenv does not work in Windows outside the Windows Subsystem for Linux.) -### The automatic installer +### Windows + +Pyenv does not officially support Windows and does not work in Windows outside +the Windows Subsystem for Linux. +Moreover, even there, the Pythons it installs are not native Windows versions +but rather Linux versions run through a compatibility layer -- +so you won't get Windows-specific functionality. + +If you're in Windows, we recommend using @kirankotari's [`pyenv-win`](https://github.com/pyenv-win/pyenv-win) fork -- +which does install native Windows Python versions. + + +### Automatic installer Visit our other project: https://github.com/pyenv/pyenv-installer From 19f74e41f0e9a8ea9516eb14e4189bb4b1121b6f Mon Sep 17 00:00:00 2001 From: Ivan Pozdeev Date: Sat, 18 Sep 2021 19:03:26 +0300 Subject: [PATCH 4/6] Update setup instructions based on user feedback --- README.md | 267 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 150 insertions(+), 117 deletions(-) diff --git a/README.md b/README.md index 7d55afac..85cb87b3 100644 --- a/README.md +++ b/README.md @@ -223,146 +223,157 @@ easy to fork and contribute any changes back upstream. **Note:** The below instructions for specific shells are designed for common shell setups; they also install shell functions into interactive shells only. - If you have an uncommon setup and/or special needs and they don't work for you, - use the guidance text and the [Advanced Configuration](#advanced-configuration) + If you have an uncommon setup and/or needs and they don't work for you, + use the [Advanced Configuration](#advanced-configuration) section below to figure out what you need to do in your specific case. - 1. **Adjust the session-wide environment for your account.** Define - the `PYENV_ROOT` environment variable to point to the path where - you cloned the Pyenv repo, add the `pyenv` command-line utility to your `PATH`, - run the output of `pyenv init --path` to enable shims. + **General MacOS note:** + Make sure that your terminal app is configured to run the shell as a login shell + (especially if you're using an alternative terminal app and/or shell). + The configuration samples for MacOS are written under this assumption and won't work otherwise. - These commands need to be added into your shell startup files in such a way - that _they are executed only once per session, by its login shell._ - This typically means they need to be added into a per-user shell-specific - `~/.*profile` file, _and_ into `~/.profile`, too, so that they are also - run by GUI managers (which typically act as a `sh` login shell). + - For **Bash**: - **MacOS note:** If you installed Pyenv with Homebrew, you don't need - to add the `PYENV_ROOT=` and `PATH=` lines. - You also don't need to add commands into `~/.profile` if your shell doesn't use it. - - - For **Bash**: + - **If your `~/.profile` sources `~/.bashrc` (Debian, Ubuntu, Mint):** + + ~~~bash + # the sed invocation inserts the lines at the start of the file + # after any initial comment lines + sed -iEe '/^([^#]|$)/ {a \ + export PYENV_ROOT="$HOME/.pyenv" + a \ + export PATH="$PYENV_ROOT/bin:$PATH" + a \ + ' -e ':a' -e '$!{n;ba};}' ~/.profile + echo 'eval "$(pyenv init --path)"' >>~/.profile + + echo 'eval "$(pyenv init -)"' >> ~/.bashrc + ~~~ + + - **If your `~/.bash_profile` sources `~/.bashrc` (Red Hat, Fedora, CentOS):** ~~~ bash + sed -iEe '/^([^#]|$)/ {a \ + export PYENV_ROOT="$HOME/.pyenv" + a \ + export PATH="$PYENV_ROOT/bin:$PATH" + a \ + ' -e ':a' -e '$!{n;ba};}' ~/.bash_profile + echo 'eval "$(pyenv init --path)"' >> ~/.bash_profile + echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile echo 'eval "$(pyenv init --path)"' >> ~/.profile + + echo 'eval "$(pyenv init -)"' >> ~/.bashrc ~~~ - - **If your `~/.profile` sources `~/.bashrc` (Debian, Ubuntu, Mint):** + - **If you have no `~/.bash_profile` and your `/etc/profile` sources `~/.bashrc` (SUSE):** - Put these lines into `~/.profile` _before_ the part that sources `~/.bashrc`: - ~~~bash - export PYENV_ROOT="$HOME/.pyenv" - export PATH="$PYENV_ROOT/bin:$PATH" - ~~~ + ~~~bash + echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile + echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile + echo 'eval "$(pyenv init --path)"' >> ~/.profile + + echo 'if command -v pyenv >/dev/null; then eval "$(pyenv init -)"; fi' >> ~/.bashrc + ~~~ - And put this line at the _bottom_ of `~/.profile`: - ~~~bash - eval "$(pyenv init --path)" - ~~~ + - **Otherwise if you have no stock `~/.profile` or `~/.bash_profile` (MacOS):** + + ~~~bash + echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile + echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile + echo 'eval "$(pyenv init --path)"' >> ~/.profile + echo 'if [ -n "$PS1" -a -n "$BASH_VERSION" ]; then source ~/.bashrc; fi' >> ~/.profile - - Alternatively, for an automated installation, you can run the following: - ~~~ bash - echo -e 'if shopt -q login_shell; then' \ - '\n export PYENV_ROOT="$HOME/.pyenv"' \ - '\n export PATH="$PYENV_ROOT/bin:$PATH"' \ - '\n eval "$(pyenv init --path)"' \ - '\nfi' >> ~/.bashrc - echo -e 'if [ -z "$BASH_VERSION" ]; then'\ - '\n export PYENV_ROOT="$HOME/.pyenv"'\ - '\n export PATH="$PYENV_ROOT/bin:$PATH"'\ - '\n eval "$(pyenv init --path)"'\ - '\nfi' >>~/.profile - ~~~ + echo 'eval "$(pyenv init -)"' >> ~/.bashrc + ~~~ - **Note:** If you have `~/.bash_profile`, make sure that it too executes the above-added commands, - e.g. by copying them there or by `source`'ing `~/.profile`. + In MacOS, make sure that your terminal app runs the shell as a login shell. - - For **Zsh**: + - **Temporary environments (CI, batch jobs):** - - **MacOS, if Pyenv is installed with Homebrew:** + In CI/build environments, paths and the environment are usually already set up for you + in one of the above ways. + You may only need to install Pyenv as a shell function into the (noninteractive) shell + that runs the batch script, and only if you need subcommands that require `pyenv` + to be a shell function (e.g. `shell` and Pyenv-Virtualenv's `activate`). - ~~~ zsh - echo 'eval "$(pyenv init --path)"' >> ~/.zprofile - ~~~ + ~~~bash + echo 'eval "$(pyenv init -)"' + ~~~ - - **MacOS, if Pyenv is installed with a Git checkout:** - - ~~~ zsh - echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zprofile - echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zprofile - echo 'eval "$(pyenv init --path)"' >> ~/.zprofile - ~~~ + **General Bash warning**: There are some systems where the `BASH_ENV` variable is configured + to point to `.bashrc`. On such systems, you should almost certainly put the + `eval "$(pyenv init -)"` line into `.bash_profile`, and **not** into `.bashrc`. Otherwise, you + may observe strange behaviour, such as `pyenv` getting into an infinite loop. + See [#264](https://github.com/pyenv/pyenv/issues/264) for details. - - **Other OSes:** + + - For **Zsh**: + + - **MacOS, if Pyenv is installed with Homebrew:** + + ~~~ zsh + echo 'eval "$(pyenv init --path)"' >> ~/.zprofile + + echo 'eval "$(pyenv init -)"' >> ~/.zshrc + ~~~ - Same as for Bash above, but add the commands into both `~/.profile` - and `~/.zprofile`. + Make sure that your terminal app runs the shell as a login shell. + + + - **MacOS, if Pyenv is installed with a Git checkout:** + + ~~~ zsh + echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zprofile + echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zprofile + echo 'eval "$(pyenv init --path)"' >> ~/.zprofile + + echo 'eval "$(pyenv init -)"' >> ~/.zshrc + ~~~ + + Make sure that your terminal app runs the shell as a login shell. + + - **Other OSes:** + + ~~~ zsh + echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zprofile + echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zprofile + echo 'eval "$(pyenv init --path)"' >> ~/.zprofile + + echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile + echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile + echo 'eval "$(pyenv init --path)"' >> ~/.profile + + echo 'eval "$(pyenv init -)"' >> ~/.zshrc + ~~~ - For **Fish shell**: Execute this interactively: + ~~~ fish set -Ux PYENV_ROOT $HOME/.pyenv set -U fish_user_paths $PYENV_ROOT/bin $fish_user_paths ~~~ And add this to `~/.config/fish/config.fish`: + ~~~ fish status is-interactive; and pyenv init --path | source + pyenv init - | source ~~~ If Fish is not your login shell, also follow the Bash/Zsh instructions to add to `~/.profile`. **Proxy note**: If you use a proxy, export `http_proxy` and `https_proxy`, too. - 2. **Add `pyenv` into your shell as a shell function** by running the output of `pyenv init -` - to enable autocompletion and subcommands that require `pyenv` to be a shell function. - The subcommands enabled by this step are those that make changes to the current shell environment. - In Pyenv, that's only `pyenv shell`; another example is `pyenv activate` from the - [Pyenv-Virtualenv](https://github.com/pyenv/pyenv-virtualenv) plugin. - - This step is optional. Run it whenever you need the above functions -- - typically at startup of any interactive shell. - In an interactive login shell, it needs to run _after_ the commands - from the previous step. - - - For **bash**: - ~~~ bash - echo 'eval "$(pyenv init -)"' >> ~/.bashrc - ~~~ - - - **If your `/etc/profile` sources `~/.bashrc` (SUSE):** - - ~~~bash - echo 'if command -v pyenv >/dev/null; then eval "$(pyenv init -)"; fi' >> ~/.bashrc - ~~~ - - - For **Zsh**: - ~~~ zsh - echo 'eval "$(pyenv init -)"' >> ~/.zshrc - ~~~ - - - For **Fish shell**: - Add this to `~/.config/fish/config.fish`: - ~~~ fish - pyenv init - | source - ~~~ - - **General warning**: There are some systems where the `BASH_ENV` variable is configured - to point to `.bashrc`. On such systems you should almost certainly put the above-mentioned line - `eval "$(pyenv init -)"` into `.bash_profile`, and **not** into `.bashrc`. Otherwise you - may observe strange behaviour, such as `pyenv` getting into an infinite loop. - See [#264](https://github.com/pyenv/pyenv/issues/264) for details. - -4. **Restart your login session for the changes to take effect.** +4. **Restart your login session for the changes to profile files to take effect.** E.g. if you're in a GUI session, you need to fully log out and log back in. - **In MacOS,** restarting terminal windows is enough (because MacOS runs shells + In MacOS, restarting terminal windows is enough (because MacOS runs shells in them as login shells by default). 5. [**Install Python build dependencies**](https://github.com/pyenv/pyenv/wiki#suggested-build-environment) before attempting to install a new Python version. @@ -445,30 +456,52 @@ profile is doing. `pyenv init` is the only command that crosses the line of loading extra commands into your shell. Coming from RVM, some of you might be -opposed to this idea. Here's what `pyenv init` actually does. -Step 1 is done by `eval "$(pyenv init --path)"`, the others are done by -`eval "$(pyenv init -)"`. +opposed to this idea. + +Also see the [Environment variables](#environment-variables) section +for the environment variables that control Pyenv's behavior. -1. **Sets up your shims path.** This is the only requirement for pyenv to - function properly. You can do this by hand by prepending - `$(pyenv root)/shims` to your `$PATH`. +* `eval "$(pyenv init --path)"`: -2. **Installs autocompletion.** This is entirely optional but pretty - useful. Sourcing `$(pyenv root)/completions/pyenv.bash` will set that - up. There is also a `$(pyenv root)/completions/pyenv.zsh` for Zsh - users. + 1. **Sets up your shims path.** This is the only requirement for pyenv to + function properly. You can do this by hand by prepending + `$(pyenv root)/shims` to your `$PATH`. + + `eval "$(pyenv init --path)"` is supposed to be run in your session's login + shell startup script -- so that all processes in the session get access to + Pyenv's functionality and it only runs once, + avoiding breaking `PATH` in nested shells + (e.g. shells started from editors/IDEs). + + In Linux, GUI managers typically act as a `sh` login shell, running + `/etc/profile` and `~/.profile` at their startup. MacOS' GUI doesn't do that, + so its terminal emulator apps run their shells as login shells by default + to compensate. -3. **Rehashes shims.** From time to time you'll need to rebuild your - shim files. Doing this on init makes sure everything is up to - date. You can always run `pyenv rehash` manually. -4. **Installs the sh dispatcher.** This bit is also optional, but allows - pyenv and plugins to change variables in your current shell, making - commands like `pyenv shell` possible. The sh dispatcher doesn't do - anything crazy like override `cd` or hack your shell prompt, but if - for some reason you need `pyenv` to be a real script rather than a - shell function, you can safely skip it. +* `eval "$(pyenv init -)"`: + + 1. **Installs autocompletion.** This is entirely optional but pretty + useful. Sourcing `$(pyenv root)/completions/pyenv.bash` will set that + up. There is also a `$(pyenv root)/completions/pyenv.zsh` for Zsh + users. + + 2. **Rehashes shims.** From time to time you'll need to rebuild your + shim files. Doing this on init makes sure everything is up to + date. You can always run `pyenv rehash` manually. + + 3. **Installs `pyenv` into the current shell as a shell function.** + This bit is also optional, but allows + pyenv and plugins to change variables in your current shell, making + commands like `pyenv shell` possible. The sh dispatcher doesn't do + anything crazy like override `cd` or hack your shell prompt, but if + for some reason you need `pyenv` to be a real script rather than a + shell function, you can safely skip it. + + `eval "$(pyenv init -)"` is supposed to run at any interactive shell's + startup (including nested shells) so that you get completion and + convenience shell functions. To see exactly what happens under the hood for yourself, run `pyenv init -` or `pyenv init --path`. From eb89256f5952ddd865b2c21d26cbf82d2c332a7e Mon Sep 17 00:00:00 2001 From: Ivan Pozdeev Date: Sun, 19 Sep 2021 00:12:06 +0300 Subject: [PATCH 5/6] Remove the sample code from pyenv init since there proved to be to many cases to fit --- libexec/pyenv-init | 63 ++-------------------------------------------- test/init.bats | 2 +- 2 files changed, 3 insertions(+), 62 deletions(-) diff --git a/libexec/pyenv-init b/libexec/pyenv-init index bc117495..840c31e0 100755 --- a/libexec/pyenv-init +++ b/libexec/pyenv-init @@ -93,68 +93,9 @@ function help_() { { echo - echo '# (The below instructions are intended for common' - echo '# shell setups. See the README for more guidance' - echo '# if they don'\''t apply and/or don'\''t work for you.)' + echo '# See the README for instructions on how to set up' + echo '# your shell environment for Pyenv.' echo - case "$shell" in - fish ) - echo "# Add pyenv executable to PATH by running" - echo "# the following interactively:" - echo - echo 'set -Ux PYENV_ROOT $HOME/.pyenv' - echo 'set -U fish_user_paths $PYENV_ROOT/bin $fish_user_paths' - echo - echo "# Load pyenv automatically by appending" - echo "# the following to ~/.config/fish/config.fish:" - echo - echo 'status is-interactive; and pyenv init --path | source' - echo 'pyenv init - | source' - echo - echo "# If fish is not your login shell," - echo "# add the following to ~/.profile:" - echo - echo 'export PYENV_ROOT="$HOME/.pyenv"' - echo 'export PATH="$PYENV_ROOT/bin:$PATH"' - echo 'eval "$(pyenv init --path)"' - echo - ;; - * ) - echo '# Add pyenv executable to PATH and' - echo '# enable shims by adding the following' - case "$shell" in - bash|ksh ) - echo '# to ~/.profile:' - ;; - * ) - echo '# to ~/.profile and '"${profile}"':' - ;; - esac - echo - echo 'export PYENV_ROOT="$HOME/.pyenv"' - echo 'export PATH="$PYENV_ROOT/bin:$PATH"' - echo 'eval "$(pyenv init --path)"' - echo - if [[ $shell == "bash" ]]; then - echo '# If your ~/.profile sources '"${rc}"',' - echo '# the lines need to be inserted before the part' - echo '# that does that. See the README for another option.' - echo - echo '# If you have '"${profile}"', make sure that it' - echo '# also executes the above lines -- e.g. by' - echo '# copying them there or by sourcing ~/.profile' - echo - fi - echo "# Load pyenv into the shell by adding" - echo "# the following to ${rc}:" - echo - echo 'eval "$(pyenv init -)"' - echo - echo '# Make sure to restart your entire logon session' - echo '# for changes to profile files to take effect.' - echo - ;; - esac } >&2 } diff --git a/test/init.bats b/test/init.bats index bcb937c1..1b597571 100755 --- a/test/init.bats +++ b/test/init.bats @@ -53,7 +53,7 @@ OUT @test "fish instructions" { run pyenv-init fish assert [ "$status" -eq 1 ] - assert_line 'pyenv init - | source' + assert_line '# See the README for instructions on how to set up' } @test "option to skip rehash" { From 76db37dbfa4025d6013f873f775ca89be6c82028 Mon Sep 17 00:00:00 2001 From: Ivan Pozdeev Date: Sun, 19 Sep 2021 01:08:26 +0300 Subject: [PATCH 6/6] Update fish instructions based on user feedback --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 85cb87b3..88a5045c 100644 --- a/README.md +++ b/README.md @@ -361,8 +361,8 @@ easy to fork and contribute any changes back upstream. And add this to `~/.config/fish/config.fish`: ~~~ fish - status is-interactive; and pyenv init --path | source - pyenv init - | source + status is-login; and pyenv init --path | source + status is-interactive; and pyenv init - | source ~~~ If Fish is not your login shell, also follow the Bash/Zsh instructions to add to `~/.profile`.