Mike Slinn

A Python Virtual Environment For Every Project

Published 2021-04-09. Last modified 2025-07-08.
Time to read: 10 minutes.

This page is part of the posts collection, categorized under Bash, Python.

Python virtual environments are cheap to make and use – unless you are unfortunate enough to program in native Windows. I have adopted the habit of making a Python virtual environment (venv) for each significant Python project, plus a default venv for trivial Python work.

Python virtualization tools have evolved over the years. Recently the uv tool has become available, and it solves the issues presented by previous generations of tools so well that I rewrote this article to focus on uv.

Why Virtualize Python?

It is better to use virtualized user- and project-specific Python instances, instead of working with a system-wide installation of Python. This allows you to install and upgrade Python packages without using supervisor privileges. Also, virtualized instances allows you to work on many different independent Python projects at the same time, without package version collisions.

Docker is over-sold. It adds unnecessary complexity to software projects. Instead of virtualizing the entire software environment, as docker attempts to do, virtualizing the Python programming environment as described in this article, Ruby rbenv, or node.js nvm are much easier and more productive approaches.

I think docker has been pushed hard in the media because it is a gateway technology to PaSS. This is a trend that PaSS vendors like AWS and Azure want to encourage, but customers are pushing back.

Uv

Uv is a convenient and fast F/OSS Python package and virtualization manager. First released only 17 months ago, it has quickly become very popular. Uv is a single program with many subcommands that replaces other package and virtualization managers, including pip, pip-tools, pipx, poetry, pyenv, twine, venv, virtualenv, and others.

This article was originally written around venv, but it has since been rewritten for uv. I switched from using venv to uv. This saves me lots of aggravation.

The uv GitHub repository is here.

The best way to install uv is by typing:

Shell
$ curl -LsSf https://astral.sh/uv/install.sh | sh
downloading uv 0.7.19 x86_64-unknown-linux-gnu
no checksums to verify
installing to /home/mslinn/.local/bin
uv
uvx
everything's installed! 

When installed this way, uv can update itself to the latest version by typing:

Shell
$ uv self update
info: Checking for updates...
success: You're on the latest version of uv (v0.7.19) 

The command syntax for uv can be displayed by typing uv -h, uv --help or uv help:

Shell
$ uv -h
An extremely fast Python package manager.
Usage: uv [OPTIONS] <COMMAND>
Commands: run Run a command or script init Create a new project add Add dependencies to the project remove Remove dependencies from the project version Read or update the project's version sync Update the project's environment lock Update the project's lockfile export Export the project's lockfile to an alternate format tree Display the project's dependency tree tool Run and install commands provided by Python packages python Manage Python versions and installations pip Manage Python packages with a pip-compatible interface venv Create a virtual environment build Build Python packages into source distributions and wheels publish Upload distributions to an index cache Manage uv's cache self Manage the uv executable help Display documentation for a command
Cache options: -n, --no-cache Avoid reading from or writing to the cache, instead using a temporary directory for the duration of the operation [env: UV_NO_CACHE=] --cache-dir <CACHE_DIR> Path to the cache directory [env: UV_CACHE_DIR=]
Python options: --managed-python Require use of uv-managed Python versions [env: UV_MANAGED_PYTHON=] --no-managed-python Disable use of uv-managed Python versions [env: UV_NO_MANAGED_PYTHON=] --no-python-downloads Disable automatic downloads of Python. [env: "UV_PYTHON_DOWNLOADS=never"]
Global options: -q, --quiet... Use quiet output -v, --verbose... Use verbose output --color <COLOR_CHOICE> Control the use of color in output [possible values: auto, always, never] --native-tls Whether to load TLS certificates from the platform's native certificate store [env: UV_NATIVE_TLS=] --offline Disable network access [env: UV_OFFLINE=] --allow-insecure-host <ALLOW_INSECURE_HOST> Allow insecure connections to a host [env: UV_INSECURE_HOST=] --no-progress Hide all progress outputs [env: UV_NO_PROGRESS=] --directory <DIRECTORY> Change to the given directory prior to running the command --project <PROJECT> Run the command within the given project directory [env: UV_PROJECT=] --config-file <CONFIG_FILE> The path to a `uv.toml` file to use for configuration [env: UV_CONFIG_FILE=] --no-config Avoid discovering configuration files (`pyproject.toml`, `uv.toml`) [env: UV_NO_CONFIG=] -h, --help Display the concise help for this command -V, --version Display the uv version
Use `uv help` for more details.

What is uvx?

Usage Example

Following along the uv usage example we can see that uv has a subcommand called init.

Shell
$ uv init example
Initialized project `example` at `/home/mslinn/example` 
$ cd example/
$ ls -alF total 8 drwxr-xr-x 1 mslinn mslinn 4096 Jul 8 11:00 ./ drwxr-xr-x 1 mslinn mslinn 4096 Jul 8 10:41 ../ drwxr-xr-x 1 mslinn mslinn 4096 Jul 8 10:41 .git/ -rw-r--r-- 1 mslinn mslinn 109 Jul 8 10:41 .gitignore -rw-r--r-- 1 mslinn mslinn 5 Jul 8 10:41 .python-version drwxr-xr-x 1 mslinn mslinn 4096 Jul 8 10:43 .venv/ -rw-r--r-- 1 mslinn mslinn 0 Jul 8 10:41 README.md -rw-r--r-- 1 mslinn mslinn 85 Jul 8 10:41 main.py -rw-r--r-- 1 mslinn mslinn 174 Jul 8 10:41 pyproject.toml -rw-r--r-- 1 mslinn mslinn 6028 Jul 8 10:41 uv.lock

One of the things that the uv init subcommand does is create an empty new Git project, just as if you had typed git init. As usual, the new Git project has no remote yet, and no commits.

Shell
$ cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true 

Uv nails down the default Python version for the new project by creating a file called .python-version. If you delete this file, the program will probably continue to work, but using the default version of Python instead of the version that is known to work.

Shell
$ cat .python-version
3.13 

Uv also creates a pyproject.toml file containing properties for the new project. You should edit this file to suit.

Shell
$ cat pyproject.toml
[project]
name = "example"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [] 

A very modest starting point for a Python program is created:

Shell
cat main.py 
def main():
print("Hello from example!")

if __name__ == "__main__": main()

Continuing with the example, I installed a Python dependency called ruff into the new Python project.

Shell
$ uv add ruff
warning: `VIRTUAL_ENV=/home/mslinn/venv/default` does not match the project environment
path `.venv` and will be ignored; use `--active` to target the active environment instead
Using CPython 3.13.3 interpreter at: /usr/bin/python3.13
Creating virtual environment at: .venv
Resolved 2 packages in 231ms
Prepared 1 package in 1.26s
Installed 1 package in 27ms
+ ruff==0.12.2 

I had neglected to deactivate my default virtual environment, which had been created by venv, beforehand. Uv notified me that it handled that issue gracefully.

I deactivated the old virtual environment so the warning message will no longer appear each time uv is run:

Shell
$ deactivate

Continuing with the example, we can run ruff:

Shell
$ uv run ruff check
All checks passed! 

Looking inside the newly created .venv directory, we see similarities to virtual environments made with the venv module:

Shell
$ tree .venv
.venv
├── CACHEDIR.TAG
├── bin
│   ├── activate
│   ├── activate.bat
│   ├── activate.csh
│   ├── activate.fish
│   ├── activate.nu
│   ├── activate.ps1
│   ├── activate_this.py
│   ├── deactivate.bat
│   ├── pydoc.bat
│   ├── python -> /usr/bin/python3.13
│   ├── python3 -> python
│   ├── python3.13 -> python
│   └── ruff
├── lib
│   └── python3.13
│   └── site-packages
│   ├── _virtualenv.pth
│   ├── _virtualenv.py
│   ├── ruff
│   │   ├── __init__.py
│   │   └── __main__.py
│   └── ruff-0.12.2.dist-info
│   ├── INSTALLER
│   ├── METADATA
│   ├── RECORD
│   ├── REQUESTED
│   ├── WHEEL
│   └── licenses
│   └── LICENSE
├── lib64 -> lib
└── pyvenv.cfg
9 directories, 25 files

Locking is the process of resolving your project’s dependencies into a lockfile. Lockfiles are called uv.lock, and contain specifications for all dependencies, including transitive dependencies. Continuing with the example, we can update the project lockfile.

Shell
$ uv lock
Resolved 2 packages in 1ms 

Notice that the uv lockfile is more complex than equivalent lockfiles for most other package managers.

uv.lock
version = 1
revision = 2
requires-python = ">=3.13"
[[package]] name = "example" version = "0.1.0" source = { virtual = "." } dependencies = [ { name = "ruff" }, ]
[package.metadata] requires-dist = [{ name = "ruff", specifier = ">=0.12.2" }]
[[package]] name = "ruff" version = "0.12.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/6c/3d/d9a195676f25d00dbfcf3cf95fdd4c685c497fcfa7e862a44ac5e4e96480/ruff-0.12.2.tar.gz", hash = "sha256:d7b4f55cd6f325cb7621244f19c873c565a08aff5a4ba9c69aa7355f3f7afd3e", size = 4432239, upload-time = "2025-07-03T16:40:19.566Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/74/b6/2098d0126d2d3318fd5bec3ad40d06c25d377d95749f7a0c5af17129b3b1/ruff-0.12.2-py3-none-linux_armv6l.whl", hash = "sha256:093ea2b221df1d2b8e7ad92fc6ffdca40a2cb10d8564477a987b44fd4008a7be", size = 10369761, upload-time = "2025-07-03T16:39:38.847Z" }, { url = "https://files.pythonhosted.org/packages/b1/4b/5da0142033dbe155dc598cfb99262d8ee2449d76920ea92c4eeb9547c208/ruff-0.12.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:09e4cf27cc10f96b1708100fa851e0daf21767e9709e1649175355280e0d950e", size = 11155659, upload-time = "2025-07-03T16:39:42.294Z" }, { url = "https://files.pythonhosted.org/packages/3e/21/967b82550a503d7c5c5c127d11c935344b35e8c521f52915fc858fb3e473/ruff-0.12.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:8ae64755b22f4ff85e9c52d1f82644abd0b6b6b6deedceb74bd71f35c24044cc", size = 10537769, upload-time = "2025-07-03T16:39:44.75Z" }, { url = "https://files.pythonhosted.org/packages/33/91/00cff7102e2ec71a4890fb7ba1803f2cdb122d82787c7d7cf8041fe8cbc1/ruff-0.12.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3eb3a6b2db4d6e2c77e682f0b988d4d61aff06860158fdb413118ca133d57922", size = 10717602, upload-time = "2025-07-03T16:39:47.652Z" }, { url = "https://files.pythonhosted.org/packages/9b/eb/928814daec4e1ba9115858adcda44a637fb9010618721937491e4e2283b8/ruff-0.12.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:73448de992d05517170fc37169cbca857dfeaeaa8c2b9be494d7bcb0d36c8f4b", size = 10198772, upload-time = "2025-07-03T16:39:49.641Z" }, { url = "https://files.pythonhosted.org/packages/50/fa/f15089bc20c40f4f72334f9145dde55ab2b680e51afb3b55422effbf2fb6/ruff-0.12.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b8b94317cbc2ae4a2771af641739f933934b03555e51515e6e021c64441532d", size = 11845173, upload-time = "2025-07-03T16:39:52.069Z" }, { url = "https://files.pythonhosted.org/packages/43/9f/1f6f98f39f2b9302acc161a4a2187b1e3a97634fe918a8e731e591841cf4/ruff-0.12.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:45fc42c3bf1d30d2008023a0a9a0cfb06bf9835b147f11fe0679f21ae86d34b1", size = 12553002, upload-time = "2025-07-03T16:39:54.551Z" }, { url = "https://files.pythonhosted.org/packages/d8/70/08991ac46e38ddd231c8f4fd05ef189b1b94be8883e8c0c146a025c20a19/ruff-0.12.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce48f675c394c37e958bf229fb5c1e843e20945a6d962cf3ea20b7a107dcd9f4", size = 12171330, upload-time = "2025-07-03T16:39:57.55Z" }, { url = "https://files.pythonhosted.org/packages/88/a9/5a55266fec474acfd0a1c73285f19dd22461d95a538f29bba02edd07a5d9/ruff-0.12.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:793d8859445ea47591272021a81391350205a4af65a9392401f418a95dfb75c9", size = 11774717, upload-time = "2025-07-03T16:39:59.78Z" }, { url = "https://files.pythonhosted.org/packages/87/e5/0c270e458fc73c46c0d0f7cf970bb14786e5fdb88c87b5e423a4bd65232b/ruff-0.12.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6932323db80484dda89153da3d8e58164d01d6da86857c79f1961934354992da", size = 11646659, upload-time = "2025-07-03T16:40:01.934Z" }, { url = "https://files.pythonhosted.org/packages/b7/b6/45ab96070c9752af37f0be364d849ed70e9ccede07675b0ec4e3ef76b63b/ruff-0.12.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6aa7e623a3a11538108f61e859ebf016c4f14a7e6e4eba1980190cacb57714ce", size = 10604012, upload-time = "2025-07-03T16:40:04.363Z" }, { url = "https://files.pythonhosted.org/packages/86/91/26a6e6a424eb147cc7627eebae095cfa0b4b337a7c1c413c447c9ebb72fd/ruff-0.12.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2a4a20aeed74671b2def096bdf2eac610c7d8ffcbf4fb0e627c06947a1d7078d", size = 10176799, upload-time = "2025-07-03T16:40:06.514Z" }, { url = "https://files.pythonhosted.org/packages/f5/0c/9f344583465a61c8918a7cda604226e77b2c548daf8ef7c2bfccf2b37200/ruff-0.12.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:71a4c550195612f486c9d1f2b045a600aeba851b298c667807ae933478fcef04", size = 11241507, upload-time = "2025-07-03T16:40:08.708Z" }, { url = "https://files.pythonhosted.org/packages/1c/b7/99c34ded8fb5f86c0280278fa89a0066c3760edc326e935ce0b1550d315d/ruff-0.12.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:4987b8f4ceadf597c927beee65a5eaf994c6e2b631df963f86d8ad1bdea99342", size = 11717609, upload-time = "2025-07-03T16:40:10.836Z" }, { url = "https://files.pythonhosted.org/packages/51/de/8589fa724590faa057e5a6d171e7f2f6cffe3287406ef40e49c682c07d89/ruff-0.12.2-py3-none-win32.whl", hash = "sha256:369ffb69b70cd55b6c3fc453b9492d98aed98062db9fec828cdfd069555f5f1a", size = 10523823, upload-time = "2025-07-03T16:40:13.203Z" }, { url = "https://files.pythonhosted.org/packages/94/47/8abf129102ae4c90cba0c2199a1a9b0fa896f6f806238d6f8c14448cc748/ruff-0.12.2-py3-none-win_amd64.whl", hash = "sha256:dca8a3b6d6dc9810ed8f328d406516bf4d660c00caeaef36eb831cf4871b0639", size = 11629831, upload-time = "2025-07-03T16:40:15.478Z" }, { url = "https://files.pythonhosted.org/packages/e2/1f/72d2946e3cc7456bb837e88000eb3437e55f80db339c840c04015a11115d/ruff-0.12.2-py3-none-win_arm64.whl", hash = "sha256:48d6c6bfb4761df68bc05ae630e24f506755e702d4fb08f08460be778c7ccb12", size = 10735334, upload-time = "2025-07-03T16:40:17.677Z" }, ]

Syncing is the process of installing a subset of packages from the lockfile into the project environment. A subdirectory tree whose root is called .venv will be created if not already present.

Continuing with the example, explicitly update the project environment. While the project environment is automatically synced, it may also be explicitly synced:

Shell
$ uv sync
Resolved 2 packages in 1ms
Audited 1 package in 0.01ms 

Up to this point, a local Git repository has been created, but there are no remote copies. If the GitHub CLI is installed, we can create a private GitHub repository, named after the current directory, and push the project to GitHub with the following incancation:

Shell
$ git add -A
$ git commit -m "Initial commit" [master (root-commit) ee73be2] Initial commit 6 files changed, 65 insertions(+) create mode 100644 .gitignore create mode 100644 .python-version create mode 100644 README.md create mode 100644 main.py create mode 100644 pyproject.toml create mode 100644 uv.lock
$ gh repo create --private --source=. --remote=origin --push ✓ Created repository mslinn/example on GitHub https://github.com/mslinn/example ✓ Added remote git@github.com:mslinn/example.git Enumerating objects: 8, done. Counting objects: 100% (8/8), done. Delta compression using up to 12 threads Compressing objects: 100% (6/6), done. Writing objects: 100% (8/8), 2.90 KiB | 990.00 KiB/s, done. Total 8 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0) To github.com:mslinn/example.git * [new branch] HEAD -> master branch 'master' set up to track 'origin/master'. ✓ Pushed commits to git@github.com:mslinn/example.git

uv python Subcommand

The help message for the uv python subcommand is:

Shell
$ uv python
Manage Python versions and installations
Usage: uv python [OPTIONS] <COMMAND>
Commands: list List the available Python installations install Download and install Python versions upgrade Upgrade installed Python versions to the latest supported patch release (requires the `--preview` flag) find Search for a Python installation pin Pin to a specific Python version dir Show the uv Python installation directory uninstall Uninstall Python versions
Cache options: -n, --no-cache Avoid reading from or writing to the cache, instead using a temporary directory for the duration of the operation [env: UV_NO_CACHE=] --cache-dir <CACHE_DIR> Path to the cache directory [env: UV_CACHE_DIR=]
Python options: --managed-python Require use of uv-managed Python versions [env: UV_MANAGED_PYTHON=] --no-managed-python Disable use of uv-managed Python versions [env: UV_NO_MANAGED_PYTHON=] --no-python-downloads Disable automatic downloads of Python. [env: "UV_PYTHON_DOWNLOADS=never"]
Global options: -q, --quiet... Use quiet output -v, --verbose... Use verbose output --color <COLOR_CHOICE> Control the use of color in output [possible values: auto, always, never] --native-tls Whether to load TLS certificates from the platform's native certificate store [env: UV_NATIVE_TLS=] --offline Disable network access [env: UV_OFFLINE=] --allow-insecure-host <ALLOW_INSECURE_HOST> Allow insecure connections to a host [env: UV_INSECURE_HOST=] --no-progress Hide all progress outputs [env: UV_NO_PROGRESS=] --directory <DIRECTORY> Change to the given directory prior to running the command --project <PROJECT> Run the command within the given project directory [env: UV_PROJECT=] --config-file <CONFIG_FILE> The path to a `uv.toml` file to use for configuration [env: UV_CONFIG_FILE=] --no-config Avoid discovering configuration files (`pyproject.toml`, `uv.toml`) [env: UV_NO_CONFIG=] -h, --help Display the concise help for this command
Use `uv help python` for more details.

Display the Python executable path used by uv. For me, this path did not exist.

Shell
$ uv python dir
/home/mslinn/.local/share/uv/python 

Display the Python executable path that uv uses to run Python programs:

Shell
$ cd $work/python/example
$ source ~/venv/default/bin/activate
(default) $ uv python find /home/mslinn/venv/default/bin/python3
(default) $ deactivate
$ uv python find /mnt/f/work/python/example/.venv/bin/python3

The above demonstrates that the uv find subcommand gives priority to an activated venv over a .venv in the current directory.

We can display all available and installed versions of Python. The following shows one installed version of Python (/usr/bin/python3.13), linked to an alias (/usr/bin/python3).

Shell
$ uv python list
cpython-3.14.0b3-linux-x86_64-gnu                 <download available>
cpython-3.14.0b3+freethreaded-linux-x86_64-gnu    <download available>
cpython-3.13.5-linux-x86_64-gnu                   <download available>
cpython-3.13.5+freethreaded-linux-x86_64-gnu      <download available>
cpython-3.13.3-linux-x86_64-gnu                   /usr/bin/python3.13
cpython-3.13.3-linux-x86_64-gnu                   /usr/bin/python3 -> python3.13
cpython-3.12.11-linux-x86_64-gnu                  <download available>
cpython-3.11.13-linux-x86_64-gnu                  <download available>
cpython-3.10.18-linux-x86_64-gnu                  <download available>
cpython-3.9.23-linux-x86_64-gnu                   <download available>
cpython-3.8.20-linux-x86_64-gnu                   <download available>
pypy-3.11.11-linux-x86_64-gnu                     <download available>
pypy-3.10.16-linux-x86_64-gnu                     <download available>
pypy-3.9.19-linux-x86_64-gnu                      <download available>
pypy-3.8.16-linux-x86_64-gnu                      <download available>
graalpy-3.11.0-linux-x86_64-gnu                   <download available>
graalpy-3.10.0-linux-x86_64-gnu                   <download available>
graalpy-3.8.5-linux-x86_64-gnu                    <download available> 

Manually Creating a Venv

The uv venv subcommand creates a venv. The following example creates the venv in $work/.venv/:

Shell
$ cd $work
$ uv venv Using CPython 3.13.3 interpreter at: /usr/bin/python3 Creating virtual environment at: .venv Activate with: source .venv/bin/activate

uv run Subcommand

The uv run help message is:

Shell
$ uv run -h
Run a command or script
Usage: uv run [OPTIONS] [COMMAND]
Options: --extra <EXTRA> Include optional dependencies from the specified extra name --all-extras Include all optional dependencies --no-extra <NO_EXTRA> Exclude the specified optional dependencies, if `--all-extras` is supplied --no-dev Disable the development dependency group --group <GROUP> Include dependencies from the specified dependency group --no-group <NO_GROUP> Disable the specified dependency group --no-default-groups Ignore the default dependency groups --only-group <ONLY_GROUP> Only include dependencies from the specified dependency group --all-groups Include dependencies from all dependency groups -m, --module Run a Python module --only-dev Only include the development dependency group --no-editable Install any editable dependencies, including the project and any workspace members, as non-editable [env: UV_NO_EDITABLE=] --exact Perform an exact sync, removing extraneous packages --env-file <ENV_FILE> Load environment variables from a `.env` file [env: UV_ENV_FILE=] --no-env-file Avoid reading environment variables from a `.env` file [env: UV_NO_ENV_FILE=] --with <WITH> Run with the given packages installed --with-editable <WITH_EDITABLE> Run with the given packages installed in editable mode --with-requirements <WITH_REQUIREMENTS> Run with all packages listed in the given `requirements.txt` files --isolated Run the command in an isolated virtual environment --active Prefer the active virtual environment over the project's virtual environment --no-sync Avoid syncing the virtual environment [env: UV_NO_SYNC=] --locked Assert that the `uv.lock` will remain unchanged [env: UV_LOCKED=] --frozen Run without updating the `uv.lock` file [env: UV_FROZEN=] -s, --script Run the given path as a Python script --gui-script Run the given path as a Python GUI script --all-packages Run the command with all workspace members installed --package <PACKAGE> Run the command in a specific package in the workspace --no-project Avoid discovering the project or workspace
Index options: --index <INDEX> The URLs to use when resolving dependencies, in addition to the default index [env: UV_INDEX=] --default-index <DEFAULT_INDEX> The URL of the default package index (by default: <https://pypi.org/simple>) [env: UV_DEFAULT_INDEX=] -i, --index-url <INDEX_URL> (Deprecated: use `--default-index` instead) The URL of the Python package index (by default: <https://pypi.org/simple>) [env: UV_INDEX_URL=] --extra-index-url <EXTRA_INDEX_URL> (Deprecated: use `--index` instead) Extra URLs of package indexes to use, in addition to `--index-url` [env: UV_EXTRA_INDEX_URL=] -f, --find-links <FIND_LINKS> Locations to search for candidate distributions, in addition to those found in the registry indexes [env: UV_FIND_LINKS=] --no-index Ignore the registry index (e.g., PyPI), instead relying on direct URL dependencies and those provided via `--find-links` --index-strategy <INDEX_STRATEGY> The strategy to use when resolving against multiple index URLs [env: UV_INDEX_STRATEGY=] [possible values: first-index, unsafe-first-match, unsafe-best-match] --keyring-provider <KEYRING_PROVIDER> Attempt to use `keyring` for authentication for index URLs [env: UV_KEYRING_PROVIDER=] [possible values: disabled, subprocess]
Resolver options: -U, --upgrade Allow package upgrades, ignoring pinned versions in any existing output file. Implies `--refresh` -P, --upgrade-package <UPGRADE_PACKAGE> Allow upgrades for a specific package, ignoring pinned versions in any existing output file. Implies `--refresh-package` --resolution <RESOLUTION> The strategy to use when selecting between the different compatible versions for a given package requirement [env: UV_RESOLUTION=] [possible values: highest, lowest, lowest-direct] --prerelease <PRERELEASE> The strategy to use when considering pre-release versions [env: UV_PRERELEASE=] [possible values: disallow, allow, if-necessary, explicit, if-necessary-or-explicit] --fork-strategy <FORK_STRATEGY> The strategy to use when selecting multiple versions of a given package across Python versions and platforms [env: UV_FORK_STRATEGY=] [possible values: fewest, requires-python] --exclude-newer <EXCLUDE_NEWER> Limit candidate packages to those that were uploaded prior to the given date [env: UV_EXCLUDE_NEWER=] --no-sources Ignore the `tool.uv.sources` table when resolving dependencies. Used to lock against the standards-compliant, publishable package metadata, as opposed to using any workspace, Git, URL, or local path sources
Installer options: --reinstall Reinstall all packages, regardless of whether they're already installed. Implies `--refresh` --reinstall-package <REINSTALL_PACKAGE> Reinstall a specific package, regardless of whether it's already installed. Implies `--refresh-package` --link-mode <LINK_MODE> The method to use when installing packages from the global cache [env: UV_LINK_MODE=] [possible values: clone, copy, hardlink, symlink] --compile-bytecode Compile Python files to bytecode after installation [env: UV_COMPILE_BYTECODE=]
Build options: -C, --config-setting <CONFIG_SETTING> Settings to pass to the PEP 517 build backend, specified as `KEY=VALUE` pairs --no-build-isolation Disable isolation when building source distributions [env: UV_NO_BUILD_ISOLATION=] --no-build-isolation-package <NO_BUILD_ISOLATION_PACKAGE> Disable isolation when building source distributions for a specific package --no-build Don't build source distributions [env: UV_NO_BUILD=] --no-build-package <NO_BUILD_PACKAGE> Don't build source distributions for a specific package [env: UV_NO_BUILD_PACKAGE=] --no-binary Don't install pre-built wheels [env: UV_NO_BINARY=] --no-binary-package <NO_BINARY_PACKAGE> Don't install pre-built wheels for a specific package [env: UV_NO_BINARY_PACKAGE=]
Cache options: -n, --no-cache Avoid reading from or writing to the cache, instead using a temporary directory for the duration of the operation [env: UV_NO_CACHE=] --cache-dir <CACHE_DIR> Path to the cache directory [env: UV_CACHE_DIR=] --refresh Refresh all cached data --refresh-package <REFRESH_PACKAGE> Refresh cached data for a specific package
Python options: -p, --python <PYTHON> The Python interpreter to use for the run environment. [env: UV_PYTHON=] --managed-python Require use of uv-managed Python versions [env: UV_MANAGED_PYTHON=] --no-managed-python Disable use of uv-managed Python versions [env: UV_NO_MANAGED_PYTHON=] --no-python-downloads Disable automatic downloads of Python. [env: "UV_PYTHON_DOWNLOADS=never"]
Global options: -q, --quiet... Use quiet output -v, --verbose... Use verbose output --color <COLOR_CHOICE> Control the use of color in output [possible values: auto, always, never] --native-tls Whether to load TLS certificates from the platform's native certificate store [env: UV_NATIVE_TLS=] --offline Disable network access [env: UV_OFFLINE=] --allow-insecure-host <ALLOW_INSECURE_HOST> Allow insecure connections to a host [env: UV_INSECURE_HOST=] --no-progress Hide all progress outputs [env: UV_NO_PROGRESS=] --directory <DIRECTORY> Change to the given directory prior to running the command --project <PROJECT> Run the command within the given project directory [env: UV_PROJECT=] --config-file <CONFIG_FILE> The path to a `uv.toml` file to use for configuration [env: UV_CONFIG_FILE=] --no-config Avoid discovering configuration files (`pyproject.toml`, `uv.toml`) [env: UV_NO_CONFIG=] -h, --help Display the concise help for this command
Use `uv help run` for more details.

Buried in the documentation is the important fact that the uv find subcommand resolves the venv very differently than the uv run command. Whereas uv find gives precedence to a currently active venv, the uv run subcommand gives precedence to the closest .venv directory, moving towards the directory root.

Here is a short Python program that displays the Python excutable path. You can edit main.py shown above so it looks like the following:

main.py
import sys
def main(): print("The current Python intepreter is " + sys.executable)

if __name__ == "__main__": main()

Now lets discover where Python is running from. That pesky warning message appears again:

Shell
$ uv run main.py
warning: `VIRTUAL_ENV=/home/mslinn/venv/default` does not match the project environment path `.venv` and will be ignored; use `--active` to target the active environment instead
The current Python intepreter is /mnt/f/work/python/example/.venv/bin/python3 

You can suppress the pesky warning with the uv run --no-active option.

Shell
$ uv run --no-active main.py
The current Python intepreter is /mnt/f/work/python/example/.venv/bin/python3 

You could define an alias to always specify the --no-active option:

~/.bash_aliases
alias uvrun='uv run --no-active'

Use the alias this way:

Shell
$ source ~/.bash_aliases
$ uvrun main.py The current Python intepreter is /mnt/f/work/python/example/.venv/bin/python3

Drop-in Pip Replacement

Uv provides a drop-in replacement for PIP. No tears will be shed for the demise of PIP.

Migrating From venv to uv

Migrating python projects to uv.

Automatic Virtual Environment Activation and Deactivation

The built-in venv module requires the user to manually activate and deactivate the appropriate virtual environment for each Python project or command. That is operationally problematic and has implementation issues. Here is an example of how to activate a virtual environment previously created by uv, run a Python program, and deactivate the virtual environment:

Clunky invocation sequence for venv
$ cd example
$ source .venv/bin/activate
(my_project) $ python main.py ...Output...
(my_project) $ deactivate $

Instead, the uv run subcommand automatically activates and deactivates the associated .venv virtual environment for each project.

Automatically activate the virtual environment before running the script and deactivate it afterwards:

Simple, reliable invocation for uv
$ cd example
$ uv run main.py Hello from example!

Note that virtual environments made by other programs can be used by uv, so long as they are PEP 405 compliant.

When running a command that mutates an environment such as uv pip sync or uv pip install, uv will search for a virtual environment in the following order:

  1. An activated virtual environment based on the VIRTUAL_ENV environment variable.
  2. An activated Conda environment based on the CONDA_PREFIX environment variable.
  3. A virtual environment at .venv in the current directory, or in the nearest parent directory.
  4. If no virtual environment is found, uv will prompt the user to create one in the current directory via uv venv.

See Discovery of Python environments for more information.

Default Virtual Environment

If you keep your Python projects in a directory tree, then placing a virtual environment in a subdirectory of the tree root will make it the default virtual environment for all subdirectories. In the following tree structure, the default Python virtual environment is highlighted.

Shell
$ cd $work
$ tree -dL 1 . ├── .venv ├── KnobKraft-orm ├── dl │ └─── .venv ├── example │ └─── .venv └── mp4ToText └─── .venv

Old Information

This remainder of this artcile describes what needed to be done before uv was available. I kept it because it provides background and motivation for the rest of this article. If you are not interested in historical information, you can stop reading this article now.

Python’s Awkward Venv Virtualization Module

Venv is an awkward tool to create isolated virtual Python environments. It has been included with Python since Python v3.3, which was released 12 years ago.

PEP 405 specifies Python’s venv virtualization module.

The two main problems I have with venv are:

  1. A virtual environment must be manually activated before running a program contained within it.
  2. The PATH environment variable often gets messed up when a virtual environment is activated. This can be extremely frustrating.

Deprecated Virtualization Modules

Python 3.6 was released 8 years ago. It deprecated the other virtualization modules, pyenv and virtualenv. Instead, use venv, as described in this article.

Extra Installation Steps for Ubuntu

Venv was included with Python on Ubuntu until Ubuntu 23.04 It virtualizes all the common Python executables.

Debian changed pip’s behavior as a result of PEP 668 – Marking Python base environments as “externally managed”. This affects Ubuntu because it is downstream. Starting with Ubuntu 23.04, you need to install venv by typing:

Shell
$ yes | sudo apt install python3.xx-venv

... where xx is the minor version number of Python that is installed.

For Python 3.12, provided with Ubuntu 24.04 (Noble Numbat), the following incantation is required:

Shell
$ yes | sudo apt install python3.12-venv

For Python 3.11, provided with Ubuntu 23.10 (Mantic Minotaur), the following incantation is required:

Shell
$ yes | sudo apt install python3.11-venv

Some software projects use meta-packages to specify version-agnostic dependencies. Perhaps Python on Ubuntu will do so in the future.

In order to virtualize pip, venv needs to invoke ensurepip, which is not installed by default on Ubuntu. On Ubuntu systems, the ensurepip command is provided by a package called python3-pip.

Shell
$ yes | sudo apt install python3-pip

You could install both of the above packages together, of course:

Shell
$ yes | sudo apt install python3.12-venv python3-pip

Manually Creating a VEnv

The following demonstrates how to create a new virtual python environment in the ~/venv/default/ directory. Intermediate directories, such as venv in this example, will be created as required.

Shell
$ python3 -m venv ~/venv/default

At this point, the virtual environment just contained executable images for Python.

Shell
$ ls ~/venv/default/**
/home/mslinn/venv/default/lib64@  /home/mslinn/venv/default/pyvenv.cfg

/home/mslinn/venv/default/bin:
Activate.ps1  activate  activate.csh  activate.fish  pip*  pip3*  pip3.10*  python@  python3@  python3.10@

/home/mslinn/venv/default/include:

/home/mslinn/venv/default/lib:
python3.10/ 

Upgrading Python

Re-installing the venv at a later date will update the version of Python in the venv. You will also need to install the appropriate python3-venv package when upgrading Python.

Each time you (re)install a virtual environment, all pip packages are removed. To prevent the loss of your installed pip packages, use pip freeze before upgrading Ubuntu, so the pip packages are memorialized in requirements.txt. After upgrading Python, run pip install to re-install the pip packages.

The following incantation runs pip freeze on every directory under ~/venv, and creates a file called requirements.txt in each venv directory:

Shell
$ find ~/venv -maxdepth 1 -mindepth 1 -type d -print0 |
  while IFS= read -r -d '' DIR; do
    source "$DIR/bin/activate"
    pip freeze > "$DIR/requirements.txt"
  done

The above incantation should be performed for each of your Python venvs before you upgrade Ubuntu, because sometimes Python venvs do not work after an upgrade. The next step should fix Python venvs that broke during an Ubuntu upgrade.

Here is an example showing the commands that must be typed to upgrade Python from v3.11 to v3.12, which you will have to do when upgrading from Ubuntu 23.10 to Ubuntu 24.04. Scroll the code window to see all the commands:

Shell
$ yes | sudo apt install python3.12-venv
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following NEW packages will be installed:
  python3.12-venv
0 upgraded, 1 newly installed, 0 to remove and 4 not upgraded.
Need to get 5676 B of archives.
After this operation, 28.7 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu noble/universe amd64 python3.12-venv amd64 3.12.3-1 [5676 B]
Fetched 5676 B in 0s (31.1 kB/s)
Selecting previously unselected package python3.12-venv.
(Reading database ... 444385 files and directories currently installed.)
Preparing to unpack .../python3.12-venv_3.12.3-1_amd64.deb ...
Unpacking python3.12-venv (3.12.3-1) ...
Setting up python3.12-venv (3.12.3-1) ...
Scanning processes...
No services need to be restarted.
No containers need to be restarted.
No user sessions are running outdated binaries.
No VM guests are running outdated hypervisor (qemu) binaries on this host.

$ find ~/venv -maxdepth 1 -type d -print0 | while IFS= read -r -d '' DIR; do python3 -m venv "$DIR" source "$DIR/bin/activate" pip install -r "$DIR/requirements.txt" done

VEnvs are Nearly Free

The cost of a venv is virtually free for all OSes except native Windows. This is because on all OSes except native Windows, the executable images are linked by default, so they do not require much storage space.

The ls command below shows that the python program in the default venv is linked to /usr/bin/python3.10.

Shell
$ ls -go ~/venv/default/bin/python
lrwxrwxrwx 1 18 Apr 9 06:01 /home/mslinn/venv/default/bin/python -> python3* 

Create a VEnv for Every Python Project

My projects are stored under the directory pointed to by $work.

My standard procedure when making a Python project called $work/blah is to also create a venv for it at within the project, at $work/blah/.venv/. I add an entry to .gitignore that merely consists of a line that says .venv/.

A bash alias could be defined called blah that makes the project directory current and activates the venv:

~/.bash_aliases
alias blah="cd $work/blah; source ./venv/bin/activate"
😁

Now you could type blah at a shell prompt, and you would be working on that project. Boom!

Deactivate a VEnv

Stop using venvs with deactivate. Notice that the prompt changes.

Shell
(aw) $ deactivate

$ 

Directory-Locked Python Virtualization

After setting up a Python virtual environment, a quick examination of the pip script shows that it is hard-coded to the directory that it was made for:

Shell
$ head -n 1 ~/venv/aw/bin/pip
#!/home/mslinn/venv/aw/bin/python 

For virtualized environments, such as Docker, this means that a Python virtual environment created without Docker can only be used within a Docker image if the path to it is the same from within the Docker image as when it was created.

Poetry and Python Virtual Environments

Python venvs are a good way to isolate Python programs from each other, so their dependencies do not clash.

The two best-known package managers for Python are PIP and Poetry. PIP is bundled with Python, while Poetry needs to be explicitly installed.

Python venvs use links to provide virtualized Python commands. Inside each venv, you will find links to programs like python, pip and library dependencies for every project that installs dependencies while the venv is active.

Poetry can:

  1. Create a venv in .venv
  2. Install specified library dependencies
  3. Run the program using the venv dependencies
  4. Publish the Python package.

Installing Poetry

If you are not careful, installing Poetry could be a chicken-and-egg race condition. You do not want Poetry to be a dependency of the venv that it manages, because it is designed to manage the libraries within the venv.

Poetry has a custom installer that creates a dedicated virtual environment for itself, and operates independently from other Python-related mechanisms. This isolated environment prevents unintentional upgrades or removals of dependencies, allowing Poetry to manage its own dependencies properly.

While it is possible to install Poetry using PIP within a venv, it is better to install Poetry system-wide. The Setup section below discusses how to do that.

PIP dependencies are often specified in a file called requirements.txt. This file ensures that a Python project uses the correct versions of dependencies by listing all the packages and their versions. Poetry uses a file called poetry.lock for the same purpose. In addition to the names and versions of the dependencies, poetry.lock also specifies the hashes of the dependant source files.

Poetry Help Messages

The top-level help message for Poetry is:

Shell
$ poetry --help
Description:
  Lists commands.
Usage: list [options] [--] [<namespace>]
Arguments: namespace The namespace name
Options: -h, --help Display help for the given command. When no command is given display help for the list command. -q, --quiet Do not output any message. -V, --version Display this application version. --ansi Force ANSI output. --no-ansi Disable ANSI output. -n, --no-interaction Do not ask any interactive question. --no-plugins Disables plugins. --no-cache Disables Poetry source caches. -C, --directory=DIRECTORY The working directory for the Poetry command (defaults to the current working directory). -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug.
Help: The list command lists all commands:
poetry list
You can also display the commands for a specific namespace:
poetry list test

The Poetry commands are:

Shell
$ poetry list
Poetry (version 1.7.1)
Usage: command [options] [arguments]
Options: -h, --help Display help for the given command. When no command is given display help for the list command. -q, --quiet Do not output any message. -V, --version Display this application version. --ansi Force ANSI output. --no-ansi Disable ANSI output. -n, --no-interaction Do not ask any interactive question. --no-plugins Disables plugins. --no-cache Disables Poetry source caches. -C, --directory=DIRECTORY The working directory for the Poetry command (defaults to the current working directory). -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug.
Available commands: about Shows information about Poetry. add Adds a new dependency to pyproject.toml. build Builds a package, as a tarball and a wheel by default. check Validates the content of the pyproject.toml file and its consistency with the poetry.lock file. config Manages configuration settings. export Exports the lock file to alternative formats. help Displays help for a command. init Creates a basic pyproject.toml file in the current directory. install Installs the project dependencies. list Lists commands. lock Locks the project dependencies. new Creates a new Python project at <path>. publish Publishes a package to a remote repository. remove Removes a package from the project dependencies. run Runs a command in the appropriate environment. search Searches for packages on remote repositories. shell Spawns a shell within the virtual environment. show Shows information about packages. update Update the dependencies as according to the pyproject.toml file. version Shows the version of the project or bumps it when a valid bump rule is provided.
cache cache clear Clears a Poetry cache by name. cache list List Poetry's caches.
debug debug info Shows debug information. debug resolve Debugs dependency resolution.
env env info Displays information about the current environment. env list Lists all virtualenvs associated with the current project. env remove Remove virtual environments associated with the project. env use Activates or creates a new virtualenv for the current project.
self self add Add additional packages to Poetry's runtime environment. self install Install locked packages (incl. addons) required by this Poetry installation. self lock Lock the Poetry installation's system requirements. self remove Remove additional packages from Poetry's runtime environment. self show Show packages from Poetry's runtime environment. self show plugins Shows information about the currently installed plugins. self update Updates Poetry to the latest version.
source source add Add source configuration for project. source remove Remove source configured for the project. source show Show information about sources configured for the project.

Detecting a Venv

Active virtual environments suppress Poetry’s behavior.

For example:

Shell
$ poetry shell
Virtual environment already activated: /home/mslinn/venv/default 

If you want to use Poetry on a project, deactivate any active virtual environment before attempting to work on the project.

Shell
$ deactivate

Here is a fragment of a script that detects if a venv is active, and disables it if so:

Bash script fragment
# Disable any activated virtual environment
VENV="$( dirname "$( which virtualenv)" )"
if [ -d "$VENV" ]; then source "$VENV/activate" && deactivate; fi

Setup

The optimal process for setting up Poetry for use in a project is:

  1. Install Poetry, preferably system-wide. I used apt to install the poetry package.
    Shell
    $ yes | sudo apt install python3-poetry
  2. Configure Poetry to manage the libraries within the venv. The poetry config help message is shown below.
  3. Use Poetry to install the library dependencies.
  4. Use Poetry to run the program using the dependencies in the venv, and/or to spawn a command-line subshell that provides access to the dependencies managed by Poetry.

The help information for the poetry config command is:

Shell
$ poetry config --help
Description:
  Manages configuration settings.
Usage: config [options] [--] [<key> [<value>...]]
Arguments: key Setting key. value Setting value.
Options: --list List configuration settings. --unset Unset configuration setting. --local Set/Get from the project's local configuration. -h, --help Display help for the given command. When no command is given display help for the list command. -q, --quiet Do not output any message. -V, --version Display this application version. --ansi Force ANSI output. --no-ansi Disable ANSI output. -n, --no-interaction Do not ask any interactive question. --no-plugins Disables plugins. --no-cache Disables Poetry source caches. -C, --directory=DIRECTORY The working directory for the Poetry command (defaults to the current working directory). -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug.
Help: This command allows you to edit the poetry config settings and repositories.
To add a repository:
poetry config repositories.foo https://bar.com/simple/
To remove a repository (repo is a short alias for repositories):
poetry config --unset repo.foo

Initializing the Poetry .venv

Imagine you have a Python project stored in $my_project.

Shell
$ cd $my_project

poetry install

The poetry install subcommand installs dependencies specified in poetry.lock, within the venv.

The help information for the poetry install command is:

Shell
$ poetry install --help
Description:
  Installs the project dependencies.
Usage: install [options]
Options: --without=WITHOUT The dependency groups to ignore. (multiple values allowed) --with=WITH The optional dependency groups to include. (multiple values allowed) --only=ONLY The only dependency groups to include. (multiple values allowed) --no-dev Do not install the development dependencies. (Deprecated) --sync Synchronize the environment with the locked packages and the specified groups. --no-root Do not install the root package (the current project). --no-directory Do not install any directory path dependencies; useful to install dependencies without source code, e.g. for caching of Docker layers) --dry-run Output the operations but do not execute anything (implicitly enables --verbose). --remove-untracked Removes packages not present in the lock file. (Deprecated) -E, --extras=EXTRAS Extra sets of dependencies to install. (multiple values allowed) --all-extras Install all extra dependencies. --only-root Exclude all dependencies. --compile Compile Python source files to bytecode. (This option has no effect if modern-installation is disabled because the old installer always compiles.) -h, --help Display help for the given command. When no command is given display help for the list command. -q, --quiet Do not output any message. -V, --version Display this application version. --ansi Force ANSI output. --no-ansi Disable ANSI output. -n, --no-interaction Do not ask any interactive question. --no-plugins Disables plugins. --no-cache Disables Poetry source caches. -C, --directory=DIRECTORY The working directory for the Poetry command (defaults to the current working directory). -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug.
Help: The install command reads the poetry.lock file from the current directory, processes it, and downloads and installs all the libraries and dependencies outlined in that file. If the file does not exist it will look for pyproject.toml and do the same.
poetry install
By default, the above command will also install the current project. To install only the dependencies and not including the current project, run the command with the --no-root option like below:
poetry install --no-root

Here is an example of using poetry install.

Shell
$ poetry install --with local
Creating virtualenv private-gpt in /mnt/f/work/my_project/.venv 

Created Files

The first time that Poetry does something, e.g. when the poetry install or poetry shell subcommands are run, Poetry creates a file in the project directory called poetry.toml. As an example, if your Python project is stored in /mnt/c/work/my_project/, poetry.toml will contain:

/mnt/c/work/my_project/poetry.toml
[virtualenvs]
create = true
in-project = true
path = "/mnt/c/work/my_project/.venv"

A file called .venv/pyvenv.cfg is also created, which looks like this:

/mnt/c/work/my_project/.venv/pyvenv.cfg
home = /usr/bin
implementation = CPython
version_info = 3.11.6.final.0
virtualenv = 20.24.1+ds
include-system-site-packages = false
base-prefix = /usr
base-exec-prefix = /usr
base-executable = /usr/bin/python3
prompt = my_project-py3.11

poetry run

The poetry run subcommand runs Python programs and scripts with the virtual environment managed by Poetry.

Shell
$ poetry run python my_program

If the first line of a script is the shebang for running Python, like this:

scripts/setup shebang
#!/usr/bin/env python3

... then we do not need to specify python or python3 on the command line.

Shell
$ poetry run my_script_containg_shebang

poetry shell

You could spawn a subshell that provides access to the dependencies managed by Poetry with the poetry shell subcommand:

Shell
$ poetry shell
Creating virtualenv my_project in /mnt/f/work/evelyn/my_project/.venv
Spawning shell within /mnt/f/work/my_project/.venv
. /mnt/f/work/my_project/.venv/bin/activate
. /mnt/f/work/my_project/.venv/bin/activate 

To deactivate the virtual environment, and exit this new shell, type CTRL-D or exit.

poetry show --tree

You can view all the dependencies for a Poetry project like this:

Shell
$ poetry show --tree
black 22.12.0 The uncompromising code formatter.
├── click >=8.0.0
│   └── colorama *
├── mypy-extensions >=0.4.3
├── pathspec >=0.9.0
└── platformdirs >=2
boto3 1.34.2 The AWS SDK for Python
├── botocore >=1.34.2,<1.35.0
│   ├── jmespath >=0.7.1,<2.0.0
│   ├── python-dateutil >=2.1,<3.0.0
│   │   └── six >=1.5
│   └── urllib3 >=1.25.4,<2.1
├── jmespath >=0.7.1,<2.0.0
└── s3transfer >=0.9.0,<0.10.0
    └── botocore >=1.33.2,<2.0a.0
        ├── jmespath >=0.7.1,<2.0.0
        ├── python-dateutil >=2.1,<3.0.0
        │   └── six >=1.5
        └── urllib3 >=1.25.4,<2.1
chromadb 0.4.20 Chroma.
├── bcrypt >=4.0.1
├── chroma-hnswlib 0.7.3
│   └── numpy *
├── fastapi >=0.95.2
│   ├── anyio >=3.7.1,<4.0.0
│   │   ├── idna >=2.8
│   │   └── sniffio >=1.1
│   ├── email-validator >=2.0.0
│   │   ├── dnspython >=2.0.0
│   │   └── idna >=2.0.0 (circular dependency aborted here)
│   ├── httpx >=0.23.0
│   │   ├── anyio * (circular dependency aborted here)
│   │   ├── certifi *
│   │   ├── h2 >=3,<5
│   │   │   ├── hpack >=4.0,<5
│   │   │   └── hyperframe >=6.0,<7
│   │   ├── httpcore ==1.*
│   │   │   ├── certifi * (circular dependency aborted here)
│   │   │   └── h11 >=0.13,<0.15
│   │   ├── idna * (circular dependency aborted here)
│   │   └── sniffio * (circular dependency aborted here)
│   ├── itsdangerous >=1.1.0
│   ├── jinja2 >=2.11.2
│   │   └── markupsafe >=2.0
│   ├── orjson >=3.2.1
│   ├── pydantic >=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0
│   │   ├── annotated-types >=0.4.0
│   │   ├── pydantic-core 2.14.5
│   │   │   └── typing-extensions >=4.6.0,<4.7.0 || >4.7.0
│   │   └── typing-extensions >=4.6.1 (circular dependency aborted here)
│   ├── pydantic-extra-types >=2.0.0
│   │   └── pydantic >=2.0.3 (circular dependency aborted here)
│   ├── pydantic-settings >=2.0.0
│   │   ├── pydantic >=2.3.0 (circular dependency aborted here)
│   │   └── python-dotenv >=0.21.0
│   ├── python-multipart >=0.0.5
│   ├── pyyaml >=5.3.1
│   ├── starlette >=0.27.0,<0.28.0
│   │   └── anyio >=3.4.0,<5 (circular dependency aborted here)
│   ├── typing-extensions >=4.5.0 (circular dependency aborted here)
│   ├── ujson >=4.0.1,<4.0.2 || >4.0.2,<4.1.0 || >4.1.0,<4.2.0 || >4.2.0,<4.3.0 || >4.3.0,<5.0.0 || >5.0.0,<5.1.0 || >5.1.0
│   └── uvicorn >=0.12.0
│       ├── click >=7.0
│       │   └── colorama *
│       ├── colorama >=0.4 (circular dependency aborted here)
│       ├── h11 >=0.8 (circular dependency aborted here)
│       ├── httptools >=0.5.0
│       ├── python-dotenv >=0.13 (circular dependency aborted here)
│       ├── pyyaml >=5.1 (circular dependency aborted here)
│       ├── uvloop >=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1
│       ├── watchfiles >=0.13
│       │   └── anyio >=3.0.0 (circular dependency aborted here)
│       └── websockets >=10.4
├── grpcio >=1.58.0
├── importlib-resources *
├── kubernetes >=28.1.0
│   ├── certifi >=14.05.14
│   ├── google-auth >=1.0.1
│   │   ├── cachetools >=2.0.0,<6.0
│   │   ├── pyasn1-modules >=0.2.1
│   │   │   └── pyasn1 >=0.4.6,<0.6.0
│   │   └── rsa >=3.1.4,<5
│   │       └── pyasn1 >=0.1.3 (circular dependency aborted here)
│   ├── oauthlib >=3.2.2
│   ├── python-dateutil >=2.5.3
│   │   └── six >=1.5
│   ├── pyyaml >=5.4.1
│   ├── requests *
│   │   ├── certifi >=2017.4.17 (circular dependency aborted here)
│   │   ├── charset-normalizer >=2,<4
│   │   ├── idna >=2.5,<4
│   │   └── urllib3 >=1.21.1,<3
│   ├── requests-oauthlib *
│   │   ├── oauthlib >=3.0.0 (circular dependency aborted here)
│   │   └── requests >=2.0.0 (circular dependency aborted here)
│   ├── six >=1.9.0 (circular dependency aborted here)
│   ├── urllib3 >=1.24.2,<2.0 (circular dependency aborted here)
│   └── websocket-client >=0.32.0,<0.40.0 || >0.40.0,<0.41.dev0 || >=0.43.dev0
├── mmh3 >=4.0.1
├── numpy >=1.22.5
├── onnxruntime >=1.14.1
│   ├── coloredlogs *
│   │   └── humanfriendly >=9.1
│   │       └── pyreadline3 *
│   ├── flatbuffers *
│   ├── numpy >=1.21.6
│   ├── packaging *
│   ├── protobuf *
│   └── sympy *
│       └── mpmath >=0.19
├── opentelemetry-api >=1.2.0
│   ├── deprecated >=1.2.6
│   │   └── wrapt >=1.10,<2
│   └── importlib-metadata >=6.0,<7.0
│       └── zipp >=0.5
├── opentelemetry-exporter-otlp-proto-grpc >=1.2.0
│   ├── backoff >=1.10.0,<3.0.0
│   ├── deprecated >=1.2.6
│   │   └── wrapt >=1.10,<2
│   ├── googleapis-common-protos >=1.52,<2.0
│   │   └── protobuf >=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0
│   ├── grpcio >=1.0.0,<2.0.0
│   ├── opentelemetry-api >=1.15,<2.0
│   │   ├── deprecated >=1.2.6 (circular dependency aborted here)
│   │   └── importlib-metadata >=6.0,<7.0
│   │       └── zipp >=0.5
│   ├── opentelemetry-exporter-otlp-proto-common 1.21.0
│   │   ├── backoff >=1.10.0,<3.0.0 (circular dependency aborted here)
│   │   └── opentelemetry-proto 1.21.0
│   │       └── protobuf >=3.19,<5.0 (circular dependency aborted here)
│   ├── opentelemetry-proto 1.21.0 (circular dependency aborted here)
│   └── opentelemetry-sdk >=1.21.0,<1.22.0
│       ├── opentelemetry-api 1.21.0 (circular dependency aborted here)
│       ├── opentelemetry-semantic-conventions 0.42b0
│       └── typing-extensions >=3.7.4
├── opentelemetry-instrumentation-fastapi >=0.41b0
│   ├── opentelemetry-api >=1.12,<2.0
│   │   ├── deprecated >=1.2.6
│   │   │   └── wrapt >=1.10,<2
│   │   └── importlib-metadata >=6.0,<7.0
│   │       └── zipp >=0.5
│   ├── opentelemetry-instrumentation 0.42b0
│   │   ├── opentelemetry-api >=1.4,<2.0 (circular dependency aborted here)
│   │   ├── setuptools >=16.0
│   │   └── wrapt >=1.0.0,<2.0.0 (circular dependency aborted here)
│   ├── opentelemetry-instrumentation-asgi 0.42b0
│   │   ├── asgiref >=3.0,<4.0
│   │   ├── opentelemetry-api >=1.12,<2.0 (circular dependency aborted here)
│   │   ├── opentelemetry-instrumentation 0.42b0 (circular dependency aborted here)
│   │   ├── opentelemetry-semantic-conventions 0.42b0
│   │   └── opentelemetry-util-http 0.42b0
│   ├── opentelemetry-semantic-conventions 0.42b0 (circular dependency aborted here)
│   └── opentelemetry-util-http 0.42b0 (circular dependency aborted here)
├── opentelemetry-sdk >=1.2.0
│   ├── opentelemetry-api 1.21.0
│   │   ├── deprecated >=1.2.6
│   │   │   └── wrapt >=1.10,<2
│   │   └── importlib-metadata >=6.0,<7.0
│   │       └── zipp >=0.5
│   ├── opentelemetry-semantic-conventions 0.42b0
│   └── typing-extensions >=3.7.4
├── overrides >=7.3.1
├── posthog >=2.4.0
│   ├── backoff >=1.10.0
│   ├── monotonic >=1.5
│   ├── python-dateutil >2.1
│   │   └── six >=1.5
│   ├── requests >=2.7,<3.0
│   │   ├── certifi >=2017.4.17
│   │   ├── charset-normalizer >=2,<4
│   │   ├── idna >=2.5,<4
│   │   └── urllib3 >=1.21.1,<3
│   └── six >=1.5 (circular dependency aborted here)
├── pulsar-client >=3.1.0
│   └── certifi *
├── pydantic >=1.9
│   ├── annotated-types >=0.4.0
│   ├── pydantic-core 2.14.5
│   │   └── typing-extensions >=4.6.0,<4.7.0 || >4.7.0
│   └── typing-extensions >=4.6.1 (circular dependency aborted here)
├── pypika >=0.48.9
├── pyyaml >=6.0.0
├── requests >=2.28
│   ├── certifi >=2017.4.17
│   ├── charset-normalizer >=2,<4
│   ├── idna >=2.5,<4
│   └── urllib3 >=1.21.1,<3
├── tenacity >=8.2.3
├── tokenizers >=0.13.2
│   └── huggingface-hub >=0.16.4,<1.0
│       ├── filelock *
│       ├── fsspec >=2023.5.0
│       │   ├── aiohttp <4.0.0a0 || >4.0.0a0,<4.0.0a1 || >4.0.0a1
│       │   │   ├── aiosignal >=1.1.2
│       │   │   │   └── frozenlist >=1.1.0
│       │   │   ├── attrs >=17.3.0
│       │   │   ├── frozenlist >=1.1.1 (circular dependency aborted here)
│       │   │   ├── multidict >=4.5,<7.0
│       │   │   └── yarl >=1.0,<2.0
│       │   │       ├── idna >=2.0
│       │   │       └── multidict >=4.0 (circular dependency aborted here)
│       │   └── requests *
│       │       ├── certifi >=2017.4.17
│       │       ├── charset-normalizer >=2,<4
│       │       ├── idna >=2.5,<4 (circular dependency aborted here)
│       │       └── urllib3 >=1.21.1,<3
│       ├── packaging >=20.9
│       ├── pyyaml >=5.1
│       ├── requests * (circular dependency aborted here)
│       ├── tqdm >=4.42.1
│       │   └── colorama *
│       └── typing-extensions >=3.7.4.3
├── tqdm >=4.65.0
│   └── colorama *
├── typer >=0.9.0
│   ├── click >=7.1.1,<9.0.0
│   │   └── colorama *
│   ├── colorama >=0.4.3,<0.5.0 (circular dependency aborted here)
│   ├── rich >=10.11.0,<14.0.0
│   │   ├── markdown-it-py >=2.2.0
│   │   │   └── mdurl >=0.1,<1.0
│   │   └── pygments >=2.13.0,<3.0.0
│   ├── shellingham >=1.3.0,<2.0.0
│   └── typing-extensions >=3.7.4.3
├── typing-extensions >=4.5.0
└── uvicorn >=0.18.3
    ├── click >=7.0
    │   └── colorama *
    ├── colorama >=0.4 (circular dependency aborted here)
    ├── h11 >=0.8
    ├── httptools >=0.5.0
    ├── python-dotenv >=0.13
    ├── pyyaml >=5.1
    ├── uvloop >=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1
    ├── watchfiles >=0.13
    │   └── anyio >=3.0.0
    │       ├── idna >=2.8
    │       └── sniffio >=1.1
    └── websockets >=10.4
fastapi 0.103.2 FastAPI framework, high performance, easy to learn, fast to code, ready for production
├── anyio >=3.7.1,<4.0.0
│   ├── idna >=2.8
│   └── sniffio >=1.1
├── email-validator >=2.0.0
│   ├── dnspython >=2.0.0
│   └── idna >=2.0.0
├── httpx >=0.23.0
│   ├── anyio *
│   │   ├── idna >=2.8
│   │   └── sniffio >=1.1
│   ├── certifi *
│   ├── h2 >=3,<5
│   │   ├── hpack >=4.0,<5
│   │   └── hyperframe >=6.0,<7
│   ├── httpcore ==1.*
│   │   ├── certifi * (circular dependency aborted here)
│   │   └── h11 >=0.13,<0.15
│   ├── idna * (circular dependency aborted here)
│   └── sniffio * (circular dependency aborted here)
├── itsdangerous >=1.1.0
├── jinja2 >=2.11.2
│   └── markupsafe >=2.0
├── orjson >=3.2.1
├── pydantic >=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0
│   ├── annotated-types >=0.4.0
│   ├── pydantic-core 2.14.5
│   │   └── typing-extensions >=4.6.0,<4.7.0 || >4.7.0
│   └── typing-extensions >=4.6.1 (circular dependency aborted here)
├── pydantic-extra-types >=2.0.0
│   └── pydantic >=2.0.3
│       ├── annotated-types >=0.4.0
│       ├── pydantic-core 2.14.5
│       │   └── typing-extensions >=4.6.0,<4.7.0 || >4.7.0
│       └── typing-extensions >=4.6.1 (circular dependency aborted here)
├── pydantic-settings >=2.0.0
│   ├── pydantic >=2.3.0
│   │   ├── annotated-types >=0.4.0
│   │   ├── pydantic-core 2.14.5
│   │   │   └── typing-extensions >=4.6.0,<4.7.0 || >4.7.0
│   │   └── typing-extensions >=4.6.1 (circular dependency aborted here)
│   └── python-dotenv >=0.21.0
├── python-multipart >=0.0.5
├── pyyaml >=5.3.1
├── starlette >=0.27.0,<0.28.0
│   └── anyio >=3.4.0,<5
│       ├── idna >=2.8
│       └── sniffio >=1.1
├── typing-extensions >=4.5.0
├── ujson >=4.0.1,<4.0.2 || >4.0.2,<4.1.0 || >4.1.0,<4.2.0 || >4.2.0,<4.3.0 || >4.3.0,<5.0.0 || >5.0.0,<5.1.0 || >5.1.0
└── uvicorn >=0.12.0
    ├── click >=7.0
    │   └── colorama *
    ├── colorama >=0.4 (circular dependency aborted here)
    ├── h11 >=0.8
    ├── httptools >=0.5.0
    ├── python-dotenv >=0.13
    ├── pyyaml >=5.1
    ├── uvloop >=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1
    ├── watchfiles >=0.13
    │   └── anyio >=3.0.0
    │       ├── idna >=2.8
    │       └── sniffio >=1.1
    └── websockets >=10.4
injector 0.21.0 Injector - Python dependency injection framework, inspired by Guice
llama-index 0.9.3 Interface between LLMs and your data
├── aiohttp >=3.8.6,<4.0.0
│   ├── aiosignal >=1.1.2
│   │   └── frozenlist >=1.1.0
│   ├── attrs >=17.3.0
│   ├── frozenlist >=1.1.1 (circular dependency aborted here)
│   ├── multidict >=4.5,<7.0
│   └── yarl >=1.0,<2.0
│       ├── idna >=2.0
│       └── multidict >=4.0 (circular dependency aborted here)
├── aiostream >=0.5.2,<0.6.0
│   └── typing-extensions *
├── beautifulsoup4 >=4.12.2,<5.0.0
│   └── soupsieve >1.2
├── dataclasses-json >=0.5.7,<0.6.0
│   ├── marshmallow >=3.18.0,<4.0.0
│   │   └── packaging >=17.0
│   └── typing-inspect >=0.4.0,<1
│       ├── mypy-extensions >=0.3.0
│       └── typing-extensions >=3.7.4
├── deprecated >=1.2.9.3
│   └── wrapt >=1.10,<2
├── fsspec >=2023.5.0
│   ├── aiohttp <4.0.0a0 || >4.0.0a0,<4.0.0a1 || >4.0.0a1
│   │   ├── aiosignal >=1.1.2
│   │   │   └── frozenlist >=1.1.0
│   │   ├── attrs >=17.3.0
│   │   ├── frozenlist >=1.1.1 (circular dependency aborted here)
│   │   ├── multidict >=4.5,<7.0
│   │   └── yarl >=1.0,<2.0
│   │       ├── idna >=2.0
│   │       └── multidict >=4.0 (circular dependency aborted here)
│   └── requests *
│       ├── certifi >=2017.4.17
│       ├── charset-normalizer >=2,<4
│       ├── idna >=2.5,<4 (circular dependency aborted here)
│       └── urllib3 >=1.21.1,<3
├── httpx *
│   ├── anyio *
│   │   ├── idna >=2.8
│   │   └── sniffio >=1.1
│   ├── certifi *
│   ├── h2 >=3,<5
│   │   ├── hpack >=4.0,<5
│   │   └── hyperframe >=6.0,<7
│   ├── httpcore ==1.*
│   │   ├── certifi * (circular dependency aborted here)
│   │   └── h11 >=0.13,<0.15
│   ├── idna * (circular dependency aborted here)
│   └── sniffio * (circular dependency aborted here)
├── nest-asyncio >=1.5.8,<2.0.0
├── nltk >=3.8.1,<4.0.0
│   ├── click *
│   │   └── colorama *
│   ├── joblib *
│   ├── regex >=2021.8.3
│   └── tqdm *
│       └── colorama * (circular dependency aborted here)
├── numpy *
├── openai >=1.1.0
│   ├── anyio >=3.5.0,<5
│   │   ├── idna >=2.8
│   │   └── sniffio >=1.1
│   ├── distro >=1.7.0,<2
│   ├── httpx >=0.23.0,<1
│   │   ├── anyio * (circular dependency aborted here)
│   │   ├── certifi *
│   │   ├── h2 >=3,<5
│   │   │   ├── hpack >=4.0,<5
│   │   │   └── hyperframe >=6.0,<7
│   │   ├── httpcore ==1.*
│   │   │   ├── certifi * (circular dependency aborted here)
│   │   │   └── h11 >=0.13,<0.15
│   │   ├── idna * (circular dependency aborted here)
│   │   └── sniffio * (circular dependency aborted here)
│   ├── pydantic >=1.9.0,<3
│   │   ├── annotated-types >=0.4.0
│   │   ├── pydantic-core 2.14.5
│   │   │   └── typing-extensions >=4.6.0,<4.7.0 || >4.7.0
│   │   └── typing-extensions >=4.6.1 (circular dependency aborted here)
│   ├── sniffio * (circular dependency aborted here)
│   ├── tqdm >4
│   │   └── colorama *
│   └── typing-extensions >=4.5,<5 (circular dependency aborted here)
├── optimum >=1.13.2,<2.0.0
│   ├── coloredlogs *
│   │   └── humanfriendly >=9.1
│   │       └── pyreadline3 *
│   ├── datasets *
│   │   ├── aiohttp *
│   │   │   ├── aiosignal >=1.1.2
│   │   │   │   └── frozenlist >=1.1.0
│   │   │   ├── attrs >=17.3.0
│   │   │   ├── frozenlist >=1.1.1 (circular dependency aborted here)
│   │   │   ├── multidict >=4.5,<7.0
│   │   │   └── yarl >=1.0,<2.0
│   │   │       ├── idna >=2.0
│   │   │       └── multidict >=4.0 (circular dependency aborted here)
│   │   ├── dill >=0.3.0,<0.3.8
│   │   ├── fsspec >=2021.11.1
│   │   │   ├── aiohttp <4.0.0a0 || >4.0.0a0,<4.0.0a1 || >4.0.0a1 (circular dependency aborted here)
│   │   │   └── requests *
│   │   │       ├── certifi >=2017.4.17
│   │   │       ├── charset-normalizer >=2,<4
│   │   │       ├── idna >=2.5,<4 (circular dependency aborted here)
│   │   │       └── urllib3 >=1.21.1,<3
│   │   ├── huggingface-hub >=0.14.0,<1.0.0
│   │   │   ├── filelock *
│   │   │   ├── fsspec >=2023.5.0 (circular dependency aborted here)
│   │   │   ├── packaging >=20.9
│   │   │   ├── pyyaml >=5.1
│   │   │   ├── requests * (circular dependency aborted here)
│   │   │   ├── tqdm >=4.42.1
│   │   │   │   └── colorama *
│   │   │   └── typing-extensions >=3.7.4.3
│   │   ├── multiprocess *
│   │   │   └── dill >=0.3.7 (circular dependency aborted here)
│   │   ├── numpy >=1.17
│   │   ├── packaging * (circular dependency aborted here)
│   │   ├── pandas *
│   │   │   ├── numpy >=1.23.2,<2 (circular dependency aborted here)
│   │   │   ├── python-dateutil >=2.8.2
│   │   │   │   └── six >=1.5
│   │   │   ├── pytz >=2020.1
│   │   │   └── tzdata >=2022.1
│   │   ├── pyarrow >=8.0.0
│   │   │   └── numpy >=1.16.6 (circular dependency aborted here)
│   │   ├── pyyaml >=5.1 (circular dependency aborted here)
│   │   ├── requests >=2.19.0 (circular dependency aborted here)
│   │   ├── tqdm >=4.62.1 (circular dependency aborted here)
│   │   └── xxhash *
│   ├── datasets >=1.2.1 (circular dependency aborted here)
│   ├── evaluate *
│   │   ├── datasets >=2.0.0 (circular dependency aborted here)
│   │   ├── dill * (circular dependency aborted here)
│   │   ├── fsspec >=2021.05.0 (circular dependency aborted here)
│   │   ├── huggingface-hub >=0.7.0 (circular dependency aborted here)
│   │   ├── multiprocess * (circular dependency aborted here)
│   │   ├── numpy >=1.17 (circular dependency aborted here)
│   │   ├── packaging * (circular dependency aborted here)
│   │   ├── pandas * (circular dependency aborted here)
│   │   ├── requests >=2.19.0 (circular dependency aborted here)
│   │   ├── responses <0.19
│   │   │   ├── requests >=2.0,<3.0 (circular dependency aborted here)
│   │   │   └── urllib3 >=1.25.10 (circular dependency aborted here)
│   │   ├── tqdm >=4.62.1 (circular dependency aborted here)
│   │   └── xxhash * (circular dependency aborted here)
│   ├── huggingface-hub >=0.8.0 (circular dependency aborted here)
│   ├── numpy * (circular dependency aborted here)
│   ├── onnx *
│   │   ├── numpy * (circular dependency aborted here)
│   │   └── protobuf >=3.20.2
│   ├── onnxruntime >=1.11.0
│   │   ├── coloredlogs * (circular dependency aborted here)
│   │   ├── flatbuffers *
│   │   ├── numpy >=1.21.6 (circular dependency aborted here)
│   │   ├── packaging * (circular dependency aborted here)
│   │   ├── protobuf * (circular dependency aborted here)
│   │   └── sympy *
│   │       └── mpmath >=0.19
│   ├── packaging * (circular dependency aborted here)
│   ├── protobuf >=3.20.1 (circular dependency aborted here)
│   ├── sympy * (circular dependency aborted here)
│   ├── torch >=1.9
│   │   ├── filelock * (circular dependency aborted here)
│   │   ├── fsspec * (circular dependency aborted here)
│   │   ├── jinja2 *
│   │   │   └── markupsafe >=2.0
│   │   ├── networkx *
│   │   ├── nvidia-cublas-cu12 12.1.3.1
│   │   ├── nvidia-cuda-cupti-cu12 12.1.105
│   │   ├── nvidia-cuda-nvrtc-cu12 12.1.105
│   │   ├── nvidia-cuda-runtime-cu12 12.1.105
│   │   ├── nvidia-cudnn-cu12 8.9.2.26
│   │   │   └── nvidia-cublas-cu12 * (circular dependency aborted here)
│   │   ├── nvidia-cufft-cu12 11.0.2.54
│   │   ├── nvidia-curand-cu12 10.3.2.106
│   │   ├── nvidia-cusolver-cu12 11.4.5.107
│   │   │   ├── nvidia-cublas-cu12 * (circular dependency aborted here)
│   │   │   ├── nvidia-cusparse-cu12 *
│   │   │   │   └── nvidia-nvjitlink-cu12 *
│   │   │   └── nvidia-nvjitlink-cu12 * (circular dependency aborted here)
│   │   ├── nvidia-cusparse-cu12 12.1.0.106 (circular dependency aborted here)
│   │   ├── nvidia-nccl-cu12 2.18.1
│   │   ├── nvidia-nvtx-cu12 12.1.105
│   │   ├── sympy * (circular dependency aborted here)
│   │   ├── triton 2.1.0
│   │   │   └── filelock * (circular dependency aborted here)
│   │   └── typing-extensions * (circular dependency aborted here)
│   └── transformers >=4.26.0
│       ├── accelerate >=0.21.0
│       │   ├── huggingface-hub * (circular dependency aborted here)
│       │   ├── numpy >=1.17 (circular dependency aborted here)
│       │   ├── packaging >=20.0 (circular dependency aborted here)
│       │   ├── psutil *
│       │   ├── pyyaml * (circular dependency aborted here)
│       │   ├── safetensors >=0.3.1
│       │   └── torch >=1.10.0 (circular dependency aborted here)
│       ├── filelock * (circular dependency aborted here)
│       ├── huggingface-hub >=0.19.3,<1.0 (circular dependency aborted here)
│       ├── numpy >=1.17 (circular dependency aborted here)
│       ├── packaging >=20.0 (circular dependency aborted here)
│       ├── protobuf * (circular dependency aborted here)
│       ├── pyyaml >=5.1 (circular dependency aborted here)
│       ├── regex !=2019.12.17
│       ├── requests * (circular dependency aborted here)
│       ├── safetensors >=0.3.1 (circular dependency aborted here)
│       ├── sentencepiece >=0.1.91,<0.1.92 || >0.1.92
│       ├── tokenizers >=0.14,<0.19
│       │   └── huggingface-hub >=0.16.4,<1.0 (circular dependency aborted here)
│       ├── torch >=1.10,<1.12.0 || >1.12.0 (circular dependency aborted here)
│       └── tqdm >=4.27 (circular dependency aborted here)
├── pandas *
│   ├── numpy >=1.23.2,<2
│   ├── python-dateutil >=2.8.2
│   │   └── six >=1.5
│   ├── pytz >=2020.1
│   └── tzdata >=2022.1
├── sentencepiece >=0.1.99,<0.2.0
├── sqlalchemy >=1.4.49
│   ├── greenlet !=0.4.17
│   └── typing-extensions >=4.2.0
├── tenacity >=8.2.0,<9.0.0
├── tiktoken >=0.3.3
│   ├── regex >=2022.1.18
│   └── requests >=2.26.0
│       ├── certifi >=2017.4.17
│       ├── charset-normalizer >=2,<4
│       ├── idna >=2.5,<4
│       └── urllib3 >=1.21.1,<3
├── transformers >=4.34.0,<5.0.0
│   ├── accelerate >=0.21.0
│   │   ├── huggingface-hub *
│   │   │   ├── filelock *
│   │   │   ├── fsspec >=2023.5.0
│   │   │   │   ├── aiohttp <4.0.0a0 || >4.0.0a0,<4.0.0a1 || >4.0.0a1
│   │   │   │   │   ├── aiosignal >=1.1.2
│   │   │   │   │   │   └── frozenlist >=1.1.0
│   │   │   │   │   ├── attrs >=17.3.0
│   │   │   │   │   ├── frozenlist >=1.1.1 (circular dependency aborted here)
│   │   │   │   │   ├── multidict >=4.5,<7.0
│   │   │   │   │   └── yarl >=1.0,<2.0
│   │   │   │   │       ├── idna >=2.0
│   │   │   │   │       └── multidict >=4.0 (circular dependency aborted here)
│   │   │   │   └── requests *
│   │   │   │       ├── certifi >=2017.4.17
│   │   │   │       ├── charset-normalizer >=2,<4
│   │   │   │       ├── idna >=2.5,<4 (circular dependency aborted here)
│   │   │   │       └── urllib3 >=1.21.1,<3
│   │   │   ├── packaging >=20.9
│   │   │   ├── pyyaml >=5.1
│   │   │   ├── requests * (circular dependency aborted here)
│   │   │   ├── tqdm >=4.42.1
│   │   │   │   └── colorama *
│   │   │   └── typing-extensions >=3.7.4.3
│   │   ├── numpy >=1.17
│   │   ├── packaging >=20.0 (circular dependency aborted here)
│   │   ├── psutil *
│   │   ├── pyyaml * (circular dependency aborted here)
│   │   ├── safetensors >=0.3.1
│   │   └── torch >=1.10.0
│   │       ├── filelock * (circular dependency aborted here)
│   │       ├── fsspec * (circular dependency aborted here)
│   │       ├── jinja2 *
│   │       │   └── markupsafe >=2.0
│   │       ├── networkx *
│   │       ├── nvidia-cublas-cu12 12.1.3.1
│   │       ├── nvidia-cuda-cupti-cu12 12.1.105
│   │       ├── nvidia-cuda-nvrtc-cu12 12.1.105
│   │       ├── nvidia-cuda-runtime-cu12 12.1.105
│   │       ├── nvidia-cudnn-cu12 8.9.2.26
│   │       │   └── nvidia-cublas-cu12 * (circular dependency aborted here)
│   │       ├── nvidia-cufft-cu12 11.0.2.54
│   │       ├── nvidia-curand-cu12 10.3.2.106
│   │       ├── nvidia-cusolver-cu12 11.4.5.107
│   │       │   ├── nvidia-cublas-cu12 * (circular dependency aborted here)
│   │       │   ├── nvidia-cusparse-cu12 *
│   │       │   │   └── nvidia-nvjitlink-cu12 *
│   │       │   └── nvidia-nvjitlink-cu12 * (circular dependency aborted here)
│   │       ├── nvidia-cusparse-cu12 12.1.0.106 (circular dependency aborted here)
│   │       ├── nvidia-nccl-cu12 2.18.1
│   │       ├── nvidia-nvtx-cu12 12.1.105
│   │       ├── sympy *
│   │       │   └── mpmath >=0.19
│   │       ├── triton 2.1.0
│   │       │   └── filelock * (circular dependency aborted here)
│   │       └── typing-extensions * (circular dependency aborted here)
│   ├── filelock * (circular dependency aborted here)
│   ├── huggingface-hub >=0.19.3,<1.0 (circular dependency aborted here)
│   ├── numpy >=1.17 (circular dependency aborted here)
│   ├── packaging >=20.0 (circular dependency aborted here)
│   ├── protobuf *
│   ├── pyyaml >=5.1 (circular dependency aborted here)
│   ├── regex !=2019.12.17
│   ├── requests * (circular dependency aborted here)
│   ├── safetensors >=0.3.1 (circular dependency aborted here)
│   ├── sentencepiece >=0.1.91,<0.1.92 || >0.1.92
│   ├── tokenizers >=0.14,<0.19
│   │   └── huggingface-hub >=0.16.4,<1.0 (circular dependency aborted here)
│   ├── torch >=1.10,<1.12.0 || >1.12.0 (circular dependency aborted here)
│   └── tqdm >=4.27 (circular dependency aborted here)
├── typing-extensions >=4.5.0
├── typing-inspect >=0.8.0
│   ├── mypy-extensions >=0.3.0
│   └── typing-extensions >=3.7.4
└── urllib3 <2
mypy 1.7.1 Optional static typing for Python
├── mypy-extensions >=1.0.0
└── typing-extensions >=4.1.0
pre-commit 2.21.0 A framework for managing and maintaining multi-language pre-commit hooks.
├── cfgv >=2.0.0
├── identify >=1.0.0
├── nodeenv >=0.11.1
│   └── setuptools *
├── pyyaml >=5.1
└── virtualenv >=20.10.0
    ├── distlib >=0.3.7,<1
    ├── filelock >=3.12.2,<4
    └── platformdirs >=3.9.1,<5
pypdf 3.17.2 A pure-python PDF library capable of splitting, merging, cropping, and transforming PDF files
pytest 7.4.3 pytest: simple powerful testing with Python
├── colorama *
├── iniconfig *
├── packaging *
└── pluggy >=0.12,<2.0
pytest-asyncio 0.21.1 Pytest support for asyncio
└── pytest >=7.0.0
    ├── colorama *
    ├── iniconfig *
    ├── packaging *
    └── pluggy >=0.12,<2.0
pytest-cov 3.0.0 Pytest plugin for measuring coverage.
├── coverage >=5.2.1
└── pytest >=4.6
    ├── colorama *
    ├── iniconfig *
    ├── packaging *
    └── pluggy >=0.12,<2.0
python-multipart 0.0.6 A streaming multipart parser for Python
pyyaml 6.0.1 YAML parser and emitter for Python
qdrant-client 1.7.0 Client library for the Qdrant vector search engine
├── grpcio >=1.41.0
├── grpcio-tools >=1.41.0
│   ├── grpcio >=1.60.0
│   ├── protobuf >=4.21.6,<5.0dev
│   └── setuptools *
├── httpx >=0.14.0
│   ├── anyio *
│   │   ├── idna >=2.8
│   │   └── sniffio >=1.1
│   ├── certifi *
│   ├── h2 >=3,<5
│   │   ├── hpack >=4.0,<5
│   │   └── hyperframe >=6.0,<7
│   ├── httpcore ==1.*
│   │   ├── certifi * (circular dependency aborted here)
│   │   └── h11 >=0.13,<0.15
│   ├── idna * (circular dependency aborted here)
│   └── sniffio * (circular dependency aborted here)
├── numpy >=1.21
├── portalocker >=2.7.0,<3.0.0
│   └── pywin32 >=226
├── pydantic >=1.10.8
│   ├── annotated-types >=0.4.0
│   ├── pydantic-core 2.14.5
│   │   └── typing-extensions >=4.6.0,<4.7.0 || >4.7.0
│   └── typing-extensions >=4.6.1 (circular dependency aborted here)
└── urllib3 >=1.26.14,<2.0.0
ruff 0.1.8 An extremely fast Python linter and code formatter, written in Rust.
types-pyyaml 6.0.12.12 Typing stubs for PyYAML
watchdog 3.0.0 Filesystem events monitoring 

poetry update

You can update all the dependencies for a Poetry project like this:

Shell
$ poetry update

For Further Reading

Python Best Practices for a New Project in 2021. This article is already becoming dated. YMMV.

Summary

  • Demonstrated how to make an alias for working with Python virtual environments (venvs) that are coupled with Python projects.
  • Deactivating the current venv was demonstrated using the deactivate command, provided with every venv.
  • Locked directories mean that Python virtual environments should normally only be created in the same environment they are intended to be used.
* indicates a required field.

Please select the following to receive Mike Slinn’s newsletter:

You can unsubscribe at any time by clicking the link in the footer of emails.

Mike Slinn uses Mailchimp as his marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp’s privacy practices.