Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configurable project virtual environment paths (e.g., for Docker) #6669

Closed
charliermarsh opened this issue Aug 27, 2024 · 13 comments · Fixed by #6834
Closed

Configurable project virtual environment paths (e.g., for Docker) #6669

charliermarsh opened this issue Aug 27, 2024 · 13 comments · Fixed by #6834
Assignees
Labels
needs-decision Undecided if this should be done

Comments

@charliermarsh
Copy link
Member

No description provided.

@zanieb zanieb added the needs-decision Undecided if this should be done label Aug 27, 2024
@gbdlin
Copy link

gbdlin commented Aug 27, 2024

Currently uv uses .venv directory inside the project to store a virtualenv. This is not compatible with all usage scenarios, for example with Docker used for local development with bind mount for project directory, virtualenv will be taken from the host instead of one built inside the docker image. This causes some problems, especially when packages installed in the host system are not compatible with ones inside docker and user wants to access uv both from inside and outside of the docker image.

@zanieb
Copy link
Member

zanieb commented Aug 28, 2024

@gbdlin

for example with Docker used for local development with bind mount for project directory, virtualenv will be taken from the host instead of one built inside the docker image

This is solvable though https://docs.astral.sh/uv/guides/integration/docker/#developing-in-a-container

@yasserfarouk
Copy link

Even though there is a solution for this need using docker, I think it is still helpful to have a way to configure the path for creating the .venv in uv. For example, I prefer to keep all my venvs under a folder in the home directory (i.e. ~/.myvenvs ) to avoid cluttering my project code folders with .venv folders which tend to increase the size of the projects folder ~/code/projects considerably. This is useful for syncing this folder across machines which I need when working with multiple servers. There are solutions to ignore .venv folders but it would be much better if they do not exist at all.
Moreover, sometimes, it may beneficial to have multiple projects sharing the same venv when they work in conjunction for a single solution that will end up being deployed together.
Also, it seems not so difficult to add this feature anyway. The responsiblity for making sure no name-conflicts can arise can be the user's. For example, if the path already exists when uv is trying to create the venv, it can just fail.

@zanieb
Copy link
Member

zanieb commented Aug 28, 2024

@yasserfarouk Thanks for sharing. That's also discussed in #1495

@gbdlin
Copy link

gbdlin commented Aug 28, 2024

@zanieb

This is solvable though https://docs.astral.sh/uv/guides/integration/docker/#developing-in-a-container

Unfortunately, this is a workaround not a solution, as it has some drawbacks.

Solution with anonymous mount for .venv directory causes a rebuild of virtualenv on first use of command with docker compose, as it fully masks the original one created inside the docker image. It is desirable to use the exact virtualenv that was included in the image to have environment as close to the production one as possible.

Solution with watch requires the newest docker compose + on some platforms has a performance penalty, as it relies on watching for file changes instead of using a native bind mount of the file system.

@terabitti
Copy link

terabitti commented Aug 28, 2024

Correct me if I’m wrong, but watch is only 1-way sync. You can’t run something like uv add from a container. The same problem occurs when running some scripts that needs to write in to your project’s directory (for example Django’s makemigrations or makemessages).

@zanieb
Copy link
Member

zanieb commented Aug 28, 2024

@gbdlin I don't think this is true

Solution with anonymous mount for .venv directory causes a rebuild of virtualenv on first use of command with docker compose, as it fully masks the original one created inside the docker image. It is desirable to use the exact virtualenv that was included in the image to have environment as close to the production one as possible.

It inherits the content from the image. I tested this case explicitly.

@zanieb
Copy link
Member

zanieb commented Aug 28, 2024

You can’t run something like uv add from a container. The same problem occurs when running some scripts that needs to write in to your project’s directory (for example Django’s makemigrations or makemessages).

Interesting, good to know. I'd say a bind mount is what you're looking for then.

@gbdlin
Copy link

gbdlin commented Aug 28, 2024

@zanieb

It inherits the content from the image. I tested this case explicitly.
With watch yes, with volume no. It will build the virtualenv again in such case, as .venv will be empty. It'll be fetched from the existing volume after container restarts, unless you clear volumes, but it's still a separately built environment outside of the docker build process.

You can check it out this way: make sure all volumes for the container are cleared, build the image with docker build or docker compose build, change project requirements by removing or modifying anything in a way you can check if it's installed from the old or new file, run the container with volumes attached, without rebuilding it, check the state of .venv directory. If uv command was run before you can access the container, you'll see .venv with updated requirements. If it didn't run, .venv directory will be empty.

Using watch works well, but as terabitti mentioned, it is only done in one direction + has performance issues on some platforms.

@zanieb
Copy link
Member

zanieb commented Aug 28, 2024

I feel like it's this simple:

❯ docker volume ls
DRIVER    VOLUME NAME
❯ docker run \
    --rm \
    --volume .:/app \
    --volume /app/.venv \
    --publish 8000:8000 \
    -it \
    $(docker build -q .) \
    uv sync
Resolved 28 packages in 0.97ms
Audited 27 packages in 0.12ms

Here I run the container with a bind mount and anonymous volume and run uv sync. Note there's nothing to do — all of the requirements are in the directory from the image build.

Similarly, you can see .venv is not empty.

❯ docker run \
    --rm \
    --volume .:/app \
    --volume /app/.venv \
    --publish 8000:8000 \
    -it \
    $(docker build -q .) \
    ls -lah .venv
total 24K
drwxr-xr-x  4 root root 4.0K Aug 28 13:48 .
drwxr-xr-x 14 root root  448 Aug 28 13:45 ..
-rw-r--r--  1 root root    1 Aug 27 01:46 .gitignore
-rw-r--r--  1 root root   43 Aug 27 01:46 CACHEDIR.TAG
drwxr-xr-x  2 root root 4.0K Aug 28 13:48 bin
drwxr-xr-x  3 root root 4.0K Aug 28 13:48 lib
lrwxrwxrwx  1 root root    3 Aug 27 01:46 lib64 -> lib
-rw-r--r--  1 root root  137 Aug 27 01:46 pyvenv.cfg

run the container with volumes attached, without rebuilding it, check the state of .venv directory. If uv command was run before you can access the container, you'll see .venv with updated requirements. If it didn't run, .venv directory will be empty.

If you don't rebuild the image, it won't reflect pyproject.toml changes in the environment until you run a uv command in it. That's the whole point — the virtual environment isn't mounted from the host to the container.

@gbdlin
Copy link

gbdlin commented Aug 28, 2024

My bad, you are indeed right. Looks like my understanding of anonymous volumes was wrong. Thank you!

@edmorley
Copy link
Contributor

Is this a dupe of #5229?

@zanieb
Copy link
Member

zanieb commented Aug 29, 2024

@edmorley sort of. If I put on my pedantic hat, this is about configuring the path of the project's virtual environment and the other one is about allowing uv sync to target arbitrary virtual environments and the discussion there seems to focus on using VIRTUAL_ENV to target the active environment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs-decision Undecided if this should be done
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants