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:

.
├── app
│   ├── poetry.lock
│   └── pyproject.toml
├── main.py
├── poetry.lock
└── pyproject.toml

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

$ poetry env info

Virtualenv
Python:         3.11.3
Implementation: CPython
Path:           /path/to/directory/.venv
Executable:     /path/to/directory/.venv/bin/python
Valid:          True

<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.

$ unset VIRTUAL_ENV
$ unset VIRTUAL_ENV
$ poetry env info

Virtualenv
Python:         3.11.3
Implementation: CPython
Path:           NA
Executable:     NA

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

$ poetry install
Creating virtualenv app in /path/to/directory/app/.venv
Installing dependencies from lock file

Package operations: 4 installs, 0 updates, 0 removals

  • Installing typing-extensions (4.11.0)
  • Installing annotated-types (0.6.0)
  • Installing pydantic-core (2.18.2)
  • Installing pydantic (2.7.1)
$ poetry env info

Virtualenv
Python:         3.11.3
Implementation: CPython
Path:           /path/to/directory/app/.venv
Executable:     /path/to/directory/app/.venv/bin/python
Valid:          True

Via Python

This idea also works from Python’s subprocess module.

Without Deleting VIRTUAL_ENV

# ./no_delete.py

import os
import subprocess

subprocess.run(
    args=["poetry", "env", "info"],
    capture_output=False,
    cwd="app",
    env=os.environ,
)
$ poetry run python no_delete.py

Virtualenv
Python:         3.11.3
Implementation: CPython
Path:           /path/to/directory/.venv
Executable:     /path/to/directory/.venv/bin/python
Valid:          True

After Deleting VIRTUAL_ENV

# ./delete.py

import os
import subprocess

env = os.environ
del env["VIRTUAL_ENV"]

subprocess.run(
    args=["poetry", "env", "info"],
    capture_output=False,
    cwd="app",
    env=env,
)
$ poetry run python delete.py

Virtualenv
Python:         3.11.3
Implementation: CPython
Path:           /path/to/directory/app/.venv
Executable:     /path/to/directory/app/.venv/bin/python
Valid:          True