smhk

Configure Poetry to use a virtualenv

TL;DR: If you want to configure Poetry to use a local virtualenv (e.g. .venv/) instead of storing the virtualenv in the cache, first you must set virtualenvs.in-project = true, second you must then re-create the virtualenv with poetry env remove <...> and poetry install.

Problem §

I have an existing Poetry project. By default, Poetry has created the virtualenv in C:\Users\squirrel\AppData\Local\pypoetry\Cache\virtualenvs\, but I want to switch this to a local .venv/ directory in the project.

Solution §

For those in a hurry, the solution is:

  1. Configure Poetry to use a local .venv/ with: poetry config virtualenvs.in-project true --local
  2. List the existing virtualenvs: poetry env info -p
  3. Delete the virtualenv that you are converting to local: poetry env remove <...>
  4. Re-create the virtualenv: poetry install

There should now be a .venv/ for your Poetry project in the local directory.

Details §

Get location of Poetry virtualenv §

First, let’s query the current location of the Poetry virtualenv for this project.

We can use poetry show -v:

PS C:\projects\my_project> poetry show -v
Using virtualenv: C:\Users\squirrel\AppData\Local\pypoetry\Cache\virtualenvs\my-project-_dCQaCL2-py3.12
structlog 24.4.0 Structured Logging for Python

Or we can use poetry env info -p:

PS C:\projects\my_project> poetry env info -p
C:\Users\squirrel\AppData\Local\pypoetry\Cache\virtualenvs\my-project-_dCQaCL2-py3.12

Additionally, we can list all the Poetry config with poetry config --list and see the default cache-dir location:

PS C:\projects\my_project> poetry config --list
cache-dir = "C:\\Users\\squirrel\\AppData\\Local\\pypoetry\\Cache"
experimental.system-git-client = false
installer.max-workers = null
installer.modern-installation = true
installer.no-binary = null
installer.parallel = true
keyring.enabled = true
solver.lazy-wheel = true
virtualenvs.create = true
virtualenvs.in-project = null
virtualenvs.options.always-copy = false
virtualenvs.options.no-pip = false
virtualenvs.options.no-setuptools = false
virtualenvs.options.system-site-packages = false
virtualenvs.path = "{cache-dir}\\virtualenvs"  # C:\Users\squirrel\AppData\Local\pypoetry\Cache\virtualenvs
virtualenvs.prefer-active-python = false
virtualenvs.prompt = "{project_name}-py{python_version}"
warnings.export = true

This also shows that virtualenvs.in-project is currently not set.

Configure Poetry to use local virtualenv §

We can use virtualenvs.in-project to tell Poetry to create the virtualenv in a local .venv/ directory rather than in cache-dir:

PS C:\projects\my_project> poetry config virtualenvs.in-project true --local

This creates a poetry.toml file (if one did not already exist) with the following:

PS C:\projects\my_project> cat poetry.toml
[virtualenvs]
in-project = true

Poetry will use the configuration in the local poetry.toml for all future Poetry commands in that project.

Checking whether it worked §

If we run poetry show -v and poetry env info -p again, we see that the cache location is still in use:

PS C:\projects\my_project> poetry show -v      
Using virtualenv: C:\Users\squirrel\AppData\Local\pypoetry\Cache\virtualenvs\my-project-_dCQaCL2-py3.12
structlog 24.4.0 Structured Logging for Python
PS C:\projects\my_project> poetry env info -p  
C:\Users\squirrel\AppData\Local\pypoetry\Cache\virtualenvs\my-project-_dCQaCL2-py3.12

We can run poetry config --list again to verify that virtualenvs.in-project was set to true:

PS C:\projects\my_project> poetry config --list
cache-dir = "C:\\Users\\squirrel\\AppData\\Local\\pypoetry\\Cache"
experimental.system-git-client = false
installer.max-workers = null
installer.modern-installation = true
installer.no-binary = null
installer.parallel = true
keyring.enabled = true
solver.lazy-wheel = true
virtualenvs.create = true
virtualenvs.in-project = true
virtualenvs.options.always-copy = false
virtualenvs.options.no-pip = false
virtualenvs.options.no-setuptools = false
virtualenvs.options.system-site-packages = false
virtualenvs.path = "{cache-dir}\\virtualenvs"  # C:\Users\squirrel\AppData\Local\pypoetry\Cache\virtualenvs
virtualenvs.prefer-active-python = false
virtualenvs.prompt = "{project_name}-py{python_version}"
warnings.export = true

It is true, yet Poetry is still using the cache virtualenv rather than a local one. So what gives?

We can try to reinstall:

PS C:\projects\my_project> poetry install
Installing dependencies from lock file

No dependencies to install or update

Installing the current project: my-project (0.1.0)

But that does not help either.

Delete and re-create the Poetry virtualenv §

The solution is to delete and re-create the virtualenv.

Even though we have set virtualenvs.in-project to true, this change in setting will not do anything if a virtualenv already exists.

First, we can list the virtualenvs:

PS C:\projects\my_project> poetry env info -p        
C:\Users\squirrel\AppData\Local\pypoetry\Cache\virtualenvs\my-project-_dCQaCL2-py3.12

Since we only have one, we can delete it with poetry env remove --all:

PS C:\projects\my_project> poetry env remove --all
Deleted virtualenv: C:\Users\squirrel\AppData\Local\pypoetry\Cache\virtualenvs\my-project-_dCQaCL2-py3.12

Now if we query poetry env info -p, we can see there is no longer a virtualenv:

PS C:\projects\my_project> poetry env info -p

So if we run poetry install, it will now create a new virtualenv at .venv/ as we desired:

PS C:\projects\my_project> poetry install
Creating virtualenv my-project in C:\projects\my_project\.venv
Installing dependencies from lock file

Package operations: 1 install, 0 updates, 0 removals

  - Installing structlog (24.4.0)

Installing the current project: my-project (0.1.0)

Finally, just to be sure, we can query poetry env info -p again:

PS C:\projects\my_project> poetry env info -p
C:\projects\my_project\.venv

All good.