-
Notifications
You must be signed in to change notification settings - Fork 959
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
Support custom venv locations for uv sync
#5229
Comments
uv sync
uv sync
Related astral-sh/rye#1211 |
÷1 and thanks for linking the related rye enhancement |
@charliermarsh I don't think this should be in scope for the first round of stabilizations. |
Here's use case I have where it would be useful. I was trying to migrate https://github.com/fastapi/full-stack-fastapi-template/ to I mount the local development directory inside the Docker container as a volume: https://github.com/fastapi/full-stack-fastapi-template/blob/master/docker-compose.override.yml#L58 This allows fast iteration on the code, as it only takes a reload of the server instead of a re-build of the Docker image to try a change. If I have a local I tried using Somewhat related, I would like to be able to use Python directly, not only through |
Makes a ton of sense, thanks @tiangolo. I think this is pretty high-priority now that the release is out.
Here, you're referring to the installed Python, like outside of the virtualenv, is that right? (Since you can always |
🚀 🎉
Yep, this part was a misunderstanding and mistake from my side. 😅 I was misinterpreting the docs. And then I was trying something that wouldn't work. But this worked: FROM tiangolo/uvicorn-gunicorn-fastapi:python3.10
# Install uv
COPY --from=ghcr.io/astral-sh/uv:0.3.0 /uv /bin/uv
WORKDIR /app/
ENV VIRTUAL_ENV=/app/.venv
# Place executables in the environment at the front of the path
ENV PATH="/app/.venv/bin:$PATH"
# Maybe copy lock file in case it doesn't exist in the repo
COPY ./pyproject.toml ./uv.lock* /app/
RUN uv sync
RUN . $VIRTUAL_ENV/bin/activate Note: it seems the build steps with full DockerfileFROM tiangolo/uvicorn-gunicorn-fastapi:python3.10
# Install uv
COPY --from=ghcr.io/astral-sh/uv:0.3.0 /uv /bin/uv
WORKDIR /app/
ENV VIRTUAL_ENV=/app/.venv
# Place executables in the environment at the front of the path
ENV PATH="/app/.venv/bin:$PATH"
# Maybe copy lock file in case it doesn't exist in the repo
COPY ./pyproject.toml ./uv.lock* /app/
# Allow installing dev dependencies to run tests
ARG INSTALL_DEV=false
RUN bash -c "if [ $INSTALL_DEV == 'true' ] ; then uv sync ; else uv sync --no-dev ; fi"
RUN . $VIRTUAL_ENV/bin/activate
ENV PYTHONPATH=/app
COPY ./scripts/ /app/
COPY ./alembic.ini /app/
COPY ./prestart.sh /app/
COPY ./tests-start.sh /app/
COPY ./app /app/app |
To add to this. Being able to configure the eg FROM python:3.12
COPY --from=ghcr.io/astral-sh/uv:0.3.0 /uv /usr/local/bin/uv
# Assuming a python project in the directory `project_name` with a `pyproject.toml` file
ENV UV_SYSTEM_PYTHON=true VIRTUAL_ENV=/opt/.venv
RUN --mount=type=bind,source=project_name,target=/project_name \
uv sync Which will result in the following error
|
@tiangolo just a heads up that providing a Note we also do cover some of this in our Docker integration guide but clearly there's room for improvement in the Docker integration story. |
Thanks @zanieb! I think what I needed would be covered in some way by activating the environment. I would like to be able to I personally actually don't like shims, I can't use About Docker, yep! Actually great docs! That's what I was basing my work on. Maybe the detail of But anyway, great job on the docs already. 👏 |
Related, re sync in dockerfile: #4028 (comment) |
@tiangolo am actually having a similar issue except we install to the system python in the Dockerfile - so I have maade a similar request to allow disabling force install into virtual env.. Here is link (Side note - absolutely love fastapi) Happy it is working for you! Also love the project team! |
@adiberk — yeah that won't work. See our documentation for a recommendation on how to activate the environment properly. tldr; # Place executables in the environment at the front of the path
ENV PATH="/app/.venv/bin:$PATH" If you're having problems with that we're happy to help. |
@zanieb Thank you! I figured out a way in the end I assume my issue is that the virtual env is getting messed up by the way we mount our volume as well as copy our folders in the Dockerfile (one or the other) |
Does adding the |
It didn’t in my case. |
Similar to #1495 (comment) , you can symlink to solve this.
|
Just to chime in with our use case: currently, we use pip-tools in our container images, where we have |
Can you elaborate here? It still mounted |
I can retest using your suggestion, however I recall in my original tests (before these comments) I had actually done that (with dockerignore) and it didn’t help. Post these comments, I simply tested by removing the .venv folder from my local and tested the docker setup suggested and still had issues. From what I can tell, this can be because of how we copy the data to docker and the volumes mounted. And so this might be specific for my project. The only thing that worked for me was running uv sync with my lockfile in a different workdir. And then setting env in my path. |
@adiberk I explored this and See the new documentation for details. If you share a complete minimal example, I'm happy to help. |
Another use-case for having a custom venv location outside of the project directory is CNBs (Cloud Native Buildpacks). With CNBs, the layer/caching model is different to
These properties allow for several benefits such as base image "rebase", finer grained cache re-use/invalidation, smaller run-images (via excluding build time only deps), the ability to support multiple languages/ecosystems (Docker multi-stage builds get messy fast when trying to build a multi-language app, since it's hard to re-use official Docker images etc). However, they do mean that the various components have to be installed into separate directory trees (rather than relying on an overlay filesystem to keep files contributed by different stages of the build separate). For example when using pip a possible layout that a Python buildpack might use, could be:
Each layer can then have its own cache invalidation logic. Any layers that are unchanged don't have to be rebuilt or even pushed to the remote. More at: Use of a venv for the app dependencies is needed due to:
As such, when we add support for uv in the future, we'll need a way to force the venv to be created outside the project directory and in its own layer. I'm mostly indifferent as to whether we have to create the venv ourselves or whether uv does that for us (so long as we can control the exact path uv creates; a generated venv path name derived from the project path/metadata like Poetry does would be more hassle). If we manually create the venv ourselves, I also don't mind too much how we'd tell uv to use that venv - for pip we'll soon be using |
@zanieb The updated guide is pretty thorough and helpful! I was actually able to get it working using a watch config which I guess is fine though it seems inconsistent sometimes and may not work as well as gunicorns hot reload setup! I will say that I did try using the new setup without watch config and trying to mount .:/app but the app failed due to loosing my env it seems. Regardless - really appreciate your help in this! |
@edmorley thank you for your thorough response. I take that feedback pretty seriously and it makes me think we'll need to expose some way to allow custom virtual environment locations. The difficulty will be in encouraging users that would be better suited not customizing the location to stay on the happy path. @adiberk I'm glad it helped! What's inconsistent about the watch setup? What happened with the mount? Feel free to open a targeted issue if something from the documentation didn't work out and we can chat over there. |
For those who care about fast multi-stage builds, I've written down my own workflow here: https://hynek.me/articles/docker-uv/ tl;dr the lack of this feature in my context is awkward but easy to work around. |
…ONMENT` (#6834) Allows configuration of the (currently hard-coded) path to the virtual environment in projects using the `UV_PROJECT_ENVIRONMENT` environment variable. If empty, we'll ignore it. If a relative path, it will be resolved relative to the workspace root. If an absolute path, we'll use that. This feature targets use in Docker images and CI. The variable is intended to be set once in an isolated system and used for all uv operations. We do not expose a CLI option or configuration file setting — we may pursue those later but I see them as lower priority. I think a system-level environment variable addresses the most pressing use-cases here. This doesn't special-case the system environment. Which means that you can use this to write to the system Python environment. I would generally strongly recommend against doing so. The insightful comment from @edmorley at #5229 (comment) provides some context on why. More generally, `uv sync` will remove packages from the environment by default. This means that if the system environment contains any packages relevant to the operation of the system (that are not dependencies of your project), `uv sync` will break it. I'd only use this in Docker or CI, if anywhere. Virtual environments have lots of benefits, and it's only [one line to "activate" them](https://docs.astral.sh/uv/guides/integration/docker/#using-the-environment). If you are considering using this feature to use Docker bind mounts for developing in containers, I would highly recommend reading our [Docker container development documentation](https://docs.astral.sh/uv/guides/integration/docker/#developing-in-a-container) first. If the solutions there do not work for you, please open an issue describing your use-case and why. We do not read `VIRTUAL_ENV` and do not have plans to at this time. Reading `VIRTUAL_ENV` is high-risk, because users can easily leave an environment active and use the uv project interface today. Reading `VIRTUAL_ENV` would be a breaking change. Additionally, uv is intentionally moving away from the concept of "active environments" and I don't think syncing to an "active" environment is the right behavior while managing projects. I plan to add a warning if `VIRTUAL_ENV` is set, to avoid confusion in this area (see #6864). This does not directly enable centrally managed virtual environments. If you set `UV_PROJECT_ENVIRONMENT` to an absolute path and use it across multiple projects, they will clobber each other's environments. However, you could use this with something like `direnv` to achieve "centrally managed" environments. I intend to build a prototype of this eventually. See #1495 for more details on this use-case. Lots of discussion about this feature in: - astral-sh/rye#371 - astral-sh/rye#1222 - astral-sh/rye#1211 - #5229 - #6669 - #6612 Follow-ups: - #6835 - #6864 - Document this in the project concept documentation (can probably re-use some of this post) Closes #6669 Closes #5229 Closes #6612
I came back just to say: thanks for writing this guide! https://docs.astral.sh/uv/guides/integration/docker/#configuring-watch-with-docker-compose 🎉 I didn't know about Docker Compose's |
Great to hear! Thank you! |
uv pip install
supports theVIRTUAL_ENV
environment variable, allowing package installation into venvs not located in the same directory as the project.uv sync
would also benefit from being able to install packages into external venvs (perhaps as a flag?)Since
uv sync
also creates venvs if they don't exist, it should do so in the custom location.The text was updated successfully, but these errors were encountered: