Updating Python using Pyenv and Poetry
- Optional: Store virtual environment in project
 - Install the preferred version of Python
 - Replace virtual environment
 - A note on shims and debugging
 - All the code
 
This isn't rocket science but is something I do infrequently enough to forget steps.
        In code blocks, lines beginning $ are commands and lines
        without show output. There are a few simple bash commands (e.g.
        cd).
      
It's assumed that you already use Pyenv and Poetry and want to change a project's Python version.
If you just want the steps, skip to all the code.
Optional: Store virtual environment in project
By default, Poetry creates virtual environments outside of projects, in Poetry's own cache directory. (Usually something like /home/ellen/.cache/pypoetry/virtualenvs.)
I've started to prefer venvs in their project directories. There's something tidy about having everything in the project directory. If I've messed something up and want to delete the venv, I don't have to remember which directory it was created in. VSCode also notices a venv created in a project and asks if I want to start using it, which means a little less configuration.
One time change:
$ poetry config virtualenvs.in-project true
      
      Install the preferred version of Python
If Pyenv was installed a while ago, there are probably new Python patch releases and maybe even a new minor version. The code uses Python 3.10 as an example.
$ pyenv update  # Update Pyenv and the list of available Python versions
$ pyenv install --list | grep "3.10"  # Check which versions of 3.10 are available
$ pyenv install 3.10.2  # This will take a while
$ cd a_project_directory
$ pyenv local 3.10.2  # Creates file .python-version, telling Pyenv which version to use when in the directory
    
      Replace virtual environment
The existing venv was created using the old version of Python and should be replaced. It's also worth telling Poetry which version of Python to use because Poetry doesn't always grab the right one. (The behaviour can depend on things like which Poetry installer you used and whether you installed Poetry or Pyenv first. More info in GitHub issues 5077 and 5190.)
The code example assumes the existing virtual environment was created in the project directory.
$ rm -rf .venv
$ poetry env use $(pyenv which python)
$ poetry install
      
      A note on shims and debugging
        Pyenv uses shims to select and run the expected version of Python. In
        other words, Pyenv intercepts calls related to Python and decides which
        Python executable to use. That's why you can type python in
        one directory and expect a Python 3.8.12 shell, while expecting that
        python in another directory will start a Python 3.10.2
        shell. That's incredibly useful but adds a little complexity.
      
        When getting an unexpected version of Python, it can be useful to check
        both the system's builtin which command and Pyenv's
        which command.
      
$ which python
/home/ellen/.pyenv/shims/python
# defers to Pyenv
$ pyenv which python
/home/ellen/.pyenv/versions/3.10.2/bin/python
# the Python exectuable that will be used
      It can also be useful to check the virtual environment's configuration file pyvenv.cfg
$ cat .venv/pyvenv.cfg
base-executable = /home/ellen/.pyenv/versions/3.10.2/bin/python
# plus other info about the configuration of the venv
      If several things are trying to set the version (e.g. environment variable and .python-version file), refer to Pyenv's documentation about how it chooses which version to use.
All the code
Assumes you have a virtual environment in the project directory.
$ pyenv update
$ pyenv install --list | grep "3.10"
$ pyenv install 3.10.2
$ cd a_project_directory
$ pyenv local 3.10.2
$ rm -rf .venv
$ poetry env use $(pyenv which python)
$ poetry install