-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Decide on semantics for workspace environment syncing (with --package
, --extra
, and --dev
)
#4730
Comments
One proposal:
Unclear if I think this proposal is reasonable as "I need extras removed when they're not activated" is sort of a niche requirement, and so making it a non-default isn't... that bad? |
Another proposal from @konstin: Alright here's the pitch:
In a way this gives us three levels in the uv CLI:
The huge drawback here: Modulo |
I want to add another perspective to this: It says the problem we're looking at is venv state. There are several things that influence the state of the venv:
Different use cases want different venvs:
Contrary to the pitch in the comment above, i've realized that for my use cases, isolation generally isn't that important, i'm fine with a single "everything venv", as long as i can run with isolation when i need it. Caching isolated temporary venvs created e.g. running |
I'd agree with @konstin - and that's something that might be useful for Airflow. For development, even for regular running of the tests, having single .venv where you can install all packages is ideal, while you have a way to run tests or scripts in separate, isolated venvs. You should be able to choose whether you want to install all packages or just one or few packages there. There are cases where you have "main" package and "extra" packages and some of the extra packages have (sometimes optional) dependencies on each other - and in this case isolated environments will not work - because even for tests you need the "other" packages as well - at least for some of the tests. So natural behaviour would be: a) run your development, autocomplete, tests in your "potentially-all-combined" environment. I think choosing which packages to install and syncing the "main" or "isolated" (if c) is supported) venvs should be purely additive - UNLESS you deliberately choose to cleanup the venv before. That should simplify all the "remove package from spec" cases - you allow the venv to have more things than needed, and if. you really want a clean version, run the installation with |
Relatedly: we need to consider how this will interact with the red-knot work... |
A few competing concerns:
|
Here's my latest proposal:
Given the criteria above, this proposal is weak on the following points:
Other than that, though, I think it does a good job on the three points above (we have a single root virtualenv that is intended to cover the package, but we build it up incrementally on-demand). It's also easy to implement (it's close to what we do today) and IMO easy to change and extend in the future. One additional behavior that I'd be open to:
This would at least enforce import boundaries for packages (but not extras). I don't see any downsides to this, other than that any manual modifications to the root |
I would avoid specifying the location, i.e., I think we'd just cache it as normal (like we do for tools) — we can determine if it should be user-facing separately. The important bit here is whether or not We probably need a separate flag from I'm feeling something like:
Regarding:
I think this is reasonable default behavior, though I'm not sure how we solve for it in the editor. We should have a flag, e.g., |
I think we should leave this as-is today, honestly. The rest seems fine to me for now. |
As of this proposal, we'd be using
For (2), we also have the I think it's probably right for What are the ideal names here? Something like...
|
Candidly, I think the easiest thing for now (which also leaves the door open for future improvements) is just to keep what we have now, but add an Everything else can kind of be layered on later if we want (e.g., always running in a (maybe empty) ephemeral environment --that seems purely additive). I personally don't want |
## Summary The culmination of #4730. We now have `uv run --isolated` which always uses a fresh environment (but includes the workspace dependencies as needed). This enables you to test with strict isolation (e.g., `uv run --isolated -p foo` will ensure that `foo` is unable to import anything that isn't an actual dependency). Closes #5430.
Arguably we have further things to discuss here, maybe we should just drop it from the project? Or just remember to revisit later? |
Yeah that's reasonable. |
(Removed from the project.) |
We had an extensive discussion about this in Discord. I'll try to summarize some of it here, but we still need to make some important decisions about how virtualenv syncing should behave for workspaces. Most of these changes aren't hard to implement, but they do have a lot of follow-on impact.
Today, we use a single virtualenv at the workspace root. When you do
uv run -p package
, we bring the environment in-sync with the necessary dependencies forpackage
. That is, we don't install the entire workspace -- only the dependencies that are required for package. This has the benefit that you can't accidentally import some other dependency from the workspace within thepackage
code (it enforces some amount of isolation).However, this syncing is purely additive. So if you run
uv run -p foo
thenuv run -p bar
, we'll install any packages necessary forbar
, but we won't uninstall the packages that we needed forfoo
(but notbar
).Extras behave similarly. So if you run
uv run -p bar --extra foo
, we'll install the extras activated byfoo
, and then leave them activated if you runuv run -p bar
.This strategy has some desirable properties (we enforce isolation on initial
uv run -p
, we only sync the necessary packages rather than building the entire workspace) but it's sort of a compromise (we don't enforce strict isolation on subsequentuv run -p
).One alternative we discussed was: creating a virtualenv per package in the workspace, on-demand. So if you did
uv run -p package
, we'd create a virtualenv inpackage
with that package's dependencies. We'd also have a virtualenv in the workspace root.This gives us the same properties that we have today, with the added benefit that it does enforce strict isolation. But there are two downsides: (1) you now have multiple virtualenvs in your project, which could confuse editors (I think this is totally fine); (2) you don't have a single virtualenv with the entire workspace installed, which means your editor could lack completions and Go-To definition for packages in the workspace (this problem also exists today); and (3) it doesn't solve the
extras
problem.(3) seems to be the critical one. Extras are kind of the same problem (stateful environments) as
-p
, but don't have a natural analog to "store the virtualenv in the package". In short, we leave extras enabled after auv run
, and this could be problematic for some packages.One solution to the "extras" problem would be to do a strict sync on every
uv run
. So if you diduv run -p foo --extra bar
and thenuv run -p foo
, we'd remove thebar
extra on that second invocation. The main downside here seems to be that youuv sync -p foo --extra bar
and thenuv run -p foo
would remove thebar
extra, which some have argued is unintuitive. (N.B.uv sync -p foo
does not exist today.)The text was updated successfully, but these errors were encountered: