astral-sh / uv

An extremely fast Python package and project manager, written in Rust.
https://docs.astral.sh/uv
Apache License 2.0
26.65k stars 773 forks source link

Add `--no-install-*` to `add`/`remove`/`run` and add env vars #6578

Open mkniewallner opened 2 months ago

mkniewallner commented 2 months ago

Some options were added in https://github.com/astral-sh/uv/issues/4028 to avoid the installation of some packages, including the project itself. Taking --no-install-project as an example, it works great when running uv sync --no-install-project, but as soon as we want to run a script/entrypoint through uv run later on, we'll still end up installing the project at some point.

For instance, if we want to build documentation for a project, running uv run mkdocs build will install the project itself, which could take some time if the project is using Rust.

Current workaround I found is to use uv run --no-project mkdocs build to avoid project discovery (assuming that uv sync --no-install-project was run beforehand), but I wonder if the 3 options added to uv sync should not also:

zanieb commented 2 months ago

Can you share more about the use-case here? We added --no-install for Docker image building and layer caching. It's not intended for you to maintain a partial environment long-term.

I'm not necessarily opposed, but I think we should be careful here — we moved fast to deliver that feature because it's critical for Docker workflows but I'm not sure I understand this use-case as much.

jfgordon2 commented 2 months ago

I also need this feature. Our use case is that we are frequently not creating python packages like this pattern assumes, but we are instead defining the dependencies using UV that are packaged alongside our source code which gets deployed into lambdas as part of serverless infrastructure. The .egg-info file that gets created for the project is unnecessary, especially since the various lambdas that compose the service will each independently define their own entry points (a single "handler" function) within the same src folder.

I'd also prefer to have the ability to set no_install_project = true in the pyproject.toml so that the project itself is never added regardless of uv command.

charliermarsh commented 2 months ago

I don't think you're looking for --no-install-project. I mean, it might work for that use-case, but that isn't why it exists. You want something like #6585: the ability to mark projects as non-packages.

mkniewallner commented 2 months ago

Can you share more about the use-case here? We added --no-install for Docker image building and layer caching. It's not intended for you to maintain a partial environment long-term.

I'm not necessarily opposed, but I think we should be careful here — we moved fast to deliver that feature because it's critical for Docker workflows but I'm not sure I understand this use-case as much.

Yep agree with not providing too many options unless they really make sense.

My use case is for https://github.com/fpgmaas/deptry, where we use maturin to build a project with a mix of Python and Rust. Building deptry itself takes quite some time, since we need to compile Rust.

In the CI, we have a dedicated job that validates documentation with mkdocs, that we set as a dev dependency. The job only needs mkdocs, but dependencies installation is so fast with uv that we don't mind installing other dependencies as well (like mypy for instance).

But when we run uv run mkdocs, we end up installing deptry itself, which takes quite some time, although we don't need to do that in this specific case.

We technically have other options, so it's not a blocker at all. For instance I guess we could:

Of course, since deptry is a library, we cannot use virtual projects in this specific case.

zanieb commented 2 months ago

Thanks for the details! We have the same problem here in the uv repository. We do

uvx --with-requirements docs/requirements.txt -- mkdocs serve -f mkdocs.public.yml

right now. Obviously this isn't ideal though. I think "project-level" tools is what you're looking for here (#3560) but we don't support that yet and need to do some design work first. I think --no-project is the "correct" workaround for now. This use-case is important, but I think uv run --no-install-* is probably not be a good long-term solution for it.

jfgordon2 commented 2 months ago

I don't think you're looking for --no-install-project. I mean, it might work for that use-case, but that isn't why it exists. You want something like #6585: the ability to mark projects as non-packages.

Ah! I think I'm just making some assumptions based on my unfamiliarity with the terminology in this project so far - thank you for pointing out that PR! I'll just patiently wait for that one.

charliermarsh commented 2 months ago

No prob, I mostly just think we can do a better job of solving your problem that way :)

zanieb commented 2 months ago

@jfgordon2 the alternate approach is available in uv 0.4.0 now.

ddorian commented 2 months ago

The change in uv 0.4.0 still doesn't fix the scenario when running uv run that will install all --dev dependencies that aren't installed usually in a container. You still need to do uv run --no-project everytime. (think ssh into a container to debug)

zanieb commented 2 months ago

There's uv run --no-dev as well. Might make sense to add UV_NO_DEV or UV_NO_PROJECT for containers. What happens if you delete the pyproject.toml and uv.lock after you setup the project? I presume we won't discover the additional dependencies then.

ddorian commented 2 months ago

I presume we won't discover the additional dependencies then.

Yes, it runs normally.

bluss commented 2 months ago

There is --frozen but is there a uv run --no-sync? Just something to say don't do anything, just use the venv as it is (but it's not no-project, I'm running w.r.t the current project's workspace and virtualenv)

zanieb commented 2 months ago

uv run --frozen should be effectively the same as uv run --no-sync

edit: The above is wrong, I misunderstood.

bluss commented 2 months ago

I thought frozen would be it, but it installs packages if they are missing. To clarify I'm looking for a flag that makes uv run never modify the virtualenv.

Here's a minimal reproducer. Yes I am deleting the venv -- making it empty -- in this example.

uv init --package testrun
# Initialized project `testrun` at `/home/user/testrun`
cd testrun/
uv sync
# Using Python 3.12.3
# Creating virtualenv at: .venv
# ...
uv venv
# Using Python 3.12.3
# Creating virtualenv at: .venv
# Activate with: source .venv/bin/activate
uv run --frozen hello
# Installed 1 package in 1ms
# Hello from testrun!

It would install more (dev-deps, other missing deps) if those existed in the example.

charliermarsh commented 2 months ago

uv run --frozen just ensures that we don't update the lock. It still syncs the environment.