uv icon indicating copy to clipboard operation
uv copied to clipboard

uv venv fails to create a venv if the directory if not empty

Open woutervh opened this issue 1 year ago • 3 comments

tested with:

  • uv --version 0.1.6
  • uv --version 0.1.7
> mkdir -p /tmp/foo
> cd /tmp/foo
> touch makefile
> uv venv .
Using Python 3.11.6 interpreter at /opt/tools/pyenv/var/repo/versions/3.11.6/bin/python3
Creating virtualenv at: .
uv::venv::creation

  × Failed to create virtualenv
  ╰─▶ The directory `.` exists, but it's not a virtualenv

The fail-message is trivially correct and expected in this case, but should not be an error th venv-creation would not overwrite any existing files or dirs.

but no problem with virtualenv:

> virtualenv .
created virtual environment CPython3.11.5.final.0-64 in 170ms
  creator CPython3Posix(dest=/tmp/foo, clear=False, no_vcs_ignore=False, global=False)
  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/opt/tools/virtualenv/var/cache)
    added seed packages: pip==23.3.2, setuptools==69.0.3, wheel==0.42.0
  activators BashActivator,CShellActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator

woutervh avatar Feb 22 '24 13:02 woutervh

Can you say more about the use-case here?

charliermarsh avatar Feb 22 '24 13:02 charliermarsh

When not developing a python project (where the venv is managed by tools like poetry), "." is probably the most common directory I use when manually creating a venv (usually via makefile/justfile).

Working on multiple laptops, and various distributions and different temporary WSL-distros and needing to support others, I see myself re-installing the same tools all the time.

I simplified my workflow to install (non-system packaged) tools to "make install". The fact that several of these tools I want to install are python-based is not important. The goal is only to make some executables available (using direct symlinks , without shims & without activation)

I moved away from tools like pipx and pipenv and I want to avoid the hidden nature of .venv or .local/share/...

my tools-repo is public:

> git clone https://github.com/libranet/libranet-tools/  /opt /tools
> cd /opt/tools/<application>
> make install

> cd /opt/tools/nvm
> make install

> cd /opt/tools/poetry
> make install

> cd /opt/tools/rye
> make install

> cd /opt/tools/virtualenv
> make install

# resulting in
> /opt/tools/<application/bin<executables>

The needed excutables are then symlinked to /opt/tools/bin which is the only dir put on $PATH

Currently most-used uv-based initial workflow is:

> uv venv foo
> cd foo
> ln -s . .venv
> uv pip install ...

But when foo is a checkout-dir with a makefile, refuses to create the venv, where 'python-m venv' or 'virtualenv' don't object.

woutervh avatar Feb 22 '24 14:02 woutervh

I encountered this issue as well, with a slightly different use case:

We use the ninja build system to build C/C++ and also manage Python dependencies via tasks: "Create a venv", "Install these requirements", "Editable-install package A", "Editable-install package B", "run A tests", "run B tests", "Wheel A", etc.

Ninja uses file timestamps to determine if a target is up-to-date, so we have "proxy" timestamp files that represent things like "this requirements.txt file was installed" because it's otherwise hard to tell whether it happened by looking at the filesystem. If pip install -r requirements.txt succeeds (as one of many examples), we'll stamp an empty file out.

We put these timestamp files inside the venv directory, inside a build_timestamps subdirectory. ninja likes to make sure that all of the output directories exist before it does its work, though, so it creates the our_venv/build_timestamps directory, which causes uv venv to then fail. I had to do some silly filesystem scripting to delete it inside the task that runs uv venv so that uv venv would see no venv directory and create it.

Anyway, it's kind of a niche corner case, but it's also very nice in that if you just want to rm -rf venv the timestamp files vanish with it, and the next invocation of ninja sees that all of the python / venv targets are dirty.

Maybe something like uv venv --permissive that skips the "directory already exists" check, indicating that "yeah, I hear what you're saying but I know some filesystem things you don't so please go ahead anyway?"

That would be safer than build-system shutil.rmtree shenanigans... :)

charlesnicholson avatar Feb 22 '24 15:02 charlesnicholson