thomaspaulin.me

How can I run commands using poetry in one virtualenv from another virtualenv?

Via Shell

Poetry uses the environment variable “VIRTUAL_ENV” for determining the activate virtual environment in many cases, this means if you delete this environment variable when running subprocesses you can load new virtual environments. Consider the following directory structure:

1.
2├── app
3│    ├── poetry.lock
4│    └── pyproject.toml
5├── main.py
6├── poetry.lock
7└── pyproject.toml

If you run poetry shell then poetry env info you’ll see the root level virtual environment is used.

 1$ poetry env info
 2
 3Virtualenv
 4Python:         3.11.3
 5Implementation: CPython
 6Path:           /path/to/directory/.venv
 7Executable:     /path/to/directory/.venv/bin/python
 8Valid:          True
 9
10<system info omitted>

If we then remove the VIRTUAL_ENV (VIRTUAL_ENV_PROMPT if you desire) environment variables the virtual environment is reset as far as poetry is concerned.

1$ unset VIRTUAL_ENV
2$ unset VIRTUAL_ENV
3$ poetry env info
4
5Virtualenv
6Python:         3.11.3
7Implementation: CPython
8Path:           NA
9Executable:     NA

This means that from the same shell we can change directory to app and run poetry install to create a new environment there.

 1$ poetry install
 2Creating virtualenv app in /path/to/directory/app/.venv
 3Installing dependencies from lock file
 4
 5Package operations: 4 installs, 0 updates, 0 removals
 6
 7  • Installing typing-extensions (4.11.0)
 8  • Installing annotated-types (0.6.0)
 9  • Installing pydantic-core (2.18.2)
10  • Installing pydantic (2.7.1)

1$ poetry env info
2
3Virtualenv
4Python:         3.11.3
5Implementation: CPython
6Path:           /path/to/directory/app/.venv
7Executable:     /path/to/directory/app/.venv/bin/python
8Valid:          True

Via Python

This idea also works from Python’s subprocess module.

Without Deleting VIRTUAL_ENV

 1# ./no_delete.py
 2
 3import os
 4import subprocess
 5
 6subprocess.run(
 7    args=["poetry", "env", "info"],
 8    capture_output=False,
 9    cwd="app",
10    env=os.environ,
11)
1$ poetry run python no_delete.py
2
3Virtualenv
4Python:         3.11.3
5Implementation: CPython
6Path:           /path/to/directory/.venv
7Executable:     /path/to/directory/.venv/bin/python
8Valid:          True

After Deleting VIRTUAL_ENV

 1# ./delete.py
 2
 3import os
 4import subprocess
 5
 6env = os.environ
 7del env["VIRTUAL_ENV"]
 8
 9subprocess.run(
10    args=["poetry", "env", "info"],
11    capture_output=False,
12    cwd="app",
13    env=env,
14)
1$ poetry run python delete.py
2
3Virtualenv
4Python:         3.11.3
5Implementation: CPython
6Path:           /path/to/directory/app/.venv
7Executable:     /path/to/directory/app/.venv/bin/python
8Valid:          True