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

Allow the creation of non-activatable envrionments #10083

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ See the [Python](#python) section for instructions on installing the Python vers
### Windows

You can install CMake from the [installers](https://cmake.org/download/) or with
`pipx install cmake`.
`uv tool install cmake`.

## Testing

Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/uv-build-frontend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ impl SourceBuild {
false,
false,
false,
false,
)?
};

Expand Down
17 changes: 16 additions & 1 deletion crates/uv-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,8 @@ pub enum Commands {
///
/// When using uv, the virtual environment does not need to be activated. uv
/// will find a virtual environment (named `.venv`) in the working directory
/// or any parent directories.
/// or any parent directories. See `--not-activatable` if you wish to disable
/// the creation of activation scripts entirely.
#[command(
alias = "virtualenv",
alias = "v",
Expand Down Expand Up @@ -2392,6 +2393,20 @@ pub struct VenvArgs {
#[arg(long)]
pub system_site_packages: bool,

#[arg(long, overrides_with("not_activatable"), hide = true)]
pub activatable: bool,

/// Disable the creation of activation scripts in the environment.
///
/// By default, uv will include activation scripts in the environment. When using `uv run`,
/// these are often not required and can be skipped with `--not-activatable`.
#[arg(
long,
value_parser = clap::builder::BoolishValueParser::new(),
overrides_with("activatable"),
)]
pub not_activatable: bool,

/// Make the virtual environment relocatable.
///
/// A relocatable virtual environment can be moved around and redistributed without
Expand Down
1 change: 1 addition & 0 deletions crates/uv-tool/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ impl InstalledTools {
false,
false,
false,
false,
)?;

Ok(venv)
Expand Down
2 changes: 1 addition & 1 deletion crates/uv-virtualenv/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "uv-virtualenv"
version = "0.0.4"
version = "0.0.5"
publish = false
description = "virtualenv creation implemented in rust"
keywords = ["virtualenv", "venv", "python"]
Expand Down
2 changes: 2 additions & 0 deletions crates/uv-virtualenv/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pub fn create_venv(
prompt: Prompt,
system_site_packages: bool,
allow_existing: bool,
activatable: bool,
relocatable: bool,
seed: bool,
) -> Result<PythonEnvironment, Error> {
Expand All @@ -63,6 +64,7 @@ pub fn create_venv(
prompt,
system_site_packages,
allow_existing,
activatable,
relocatable,
seed,
)?;
Expand Down
85 changes: 45 additions & 40 deletions crates/uv-virtualenv/src/virtualenv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ pub(crate) fn create(
prompt: Prompt,
system_site_packages: bool,
allow_existing: bool,
activatable: bool,
relocatable: bool,
seed: bool,
) -> Result<VirtualEnvironment, Error> {
Expand Down Expand Up @@ -290,47 +291,51 @@ pub(crate) fn create(
compile_error!("Only Windows and Unix are supported")
}

// Add all the activate scripts for different shells
for (name, template) in ACTIVATE_TEMPLATES {
let path_sep = if cfg!(windows) { ";" } else { ":" };

let relative_site_packages = [
interpreter.virtualenv().purelib.as_path(),
interpreter.virtualenv().platlib.as_path(),
]
.iter()
.dedup()
.map(|path| {
pathdiff::diff_paths(path, &interpreter.virtualenv().scripts)
.expect("Failed to calculate relative path to site-packages")
})
.map(|path| path.simplified().to_str().unwrap().replace('\\', "\\\\"))
.join(path_sep);

let virtual_env_dir = match (relocatable, name.to_owned()) {
(true, "activate") => {
r#"'"$(dirname -- "$(dirname -- "$(realpath -- "$SCRIPT_PATH")")")"'"#.to_string()
}
(true, "activate.bat") => r"%~dp0..".to_string(),
(true, "activate.fish") => {
r#"'"$(dirname -- "$(cd "$(dirname -- "$(status -f)")"; and pwd)")"'"#.to_string()
}
// Note:
// * relocatable activate scripts appear not to be possible in csh and nu shell
// * `activate.ps1` is already relocatable by default.
_ => escape_posix_for_single_quotes(location.simplified().to_str().unwrap()),
};
if activatable {
// Add all the activate scripts for different shells
for (name, template) in ACTIVATE_TEMPLATES {
let path_sep = if cfg!(windows) { ";" } else { ":" };

let relative_site_packages = [
interpreter.virtualenv().purelib.as_path(),
interpreter.virtualenv().platlib.as_path(),
]
.iter()
.dedup()
.map(|path| {
pathdiff::diff_paths(path, &interpreter.virtualenv().scripts)
.expect("Failed to calculate relative path to site-packages")
})
.map(|path| path.simplified().to_str().unwrap().replace('\\', "\\\\"))
.join(path_sep);

let virtual_env_dir = match (relocatable, name.to_owned()) {
(true, "activate") => {
r#"'"$(dirname -- "$(dirname -- "$(realpath -- "$SCRIPT_PATH")")")"'"#
.to_string()
}
(true, "activate.bat") => r"%~dp0..".to_string(),
(true, "activate.fish") => {
r#"'"$(dirname -- "$(cd "$(dirname -- "$(status -f)")"; and pwd)")"'"#
.to_string()
}
// Note:
// * relocatable activate scripts appear not to be possible in csh and nu shell
// * `activate.ps1` is already relocatable by default.
_ => escape_posix_for_single_quotes(location.simplified().to_str().unwrap()),
};

let activator = template
.replace("{{ VIRTUAL_ENV_DIR }}", &virtual_env_dir)
.replace("{{ BIN_NAME }}", bin_name)
.replace(
"{{ VIRTUAL_PROMPT }}",
prompt.as_deref().unwrap_or_default(),
)
.replace("{{ PATH_SEP }}", path_sep)
.replace("{{ RELATIVE_SITE_PACKAGES }}", &relative_site_packages);
fs::write(scripts.join(name), activator)?;
let activator = template
.replace("{{ VIRTUAL_ENV_DIR }}", &virtual_env_dir)
.replace("{{ BIN_NAME }}", bin_name)
.replace(
"{{ VIRTUAL_PROMPT }}",
prompt.as_deref().unwrap_or_default(),
)
.replace("{{ PATH_SEP }}", path_sep)
.replace("{{ RELATIVE_SITE_PACKAGES }}", &relative_site_packages);
fs::write(scripts.join(name), activator)?;
}
}

let mut pyvenv_cfg_data: Vec<(String, String)> = vec![
Expand Down
1 change: 1 addition & 0 deletions crates/uv/src/commands/project/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ impl CachedEnvironment {
uv_virtualenv::Prompt::None,
false,
false,
false,
true,
false,
)?;
Expand Down
1 change: 1 addition & 0 deletions crates/uv/src/commands/project/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,7 @@ pub(crate) async fn get_or_init_environment(
prompt,
false,
false,
true,
false,
false,
)?)
Expand Down
4 changes: 4 additions & 0 deletions crates/uv/src/commands/project/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ pub(crate) async fn run(
false,
false,
false,
false,
)?;

Some(environment.into_interpreter())
Expand Down Expand Up @@ -585,6 +586,7 @@ pub(crate) async fn run(
false,
false,
false,
false,
)?
} else {
// If we're not isolating the environment, reuse the base environment for the
Expand Down Expand Up @@ -817,6 +819,7 @@ pub(crate) async fn run(
false,
false,
false,
false,
)?;
venv.into_interpreter()
} else {
Expand Down Expand Up @@ -867,6 +870,7 @@ pub(crate) async fn run(
false,
false,
false,
false,
)?
}
Some(spec) => {
Expand Down
60 changes: 33 additions & 27 deletions crates/uv/src/commands/venv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ pub(crate) async fn venv(
no_project: bool,
cache: &Cache,
printer: Printer,
activatable: bool,
relocatable: bool,
preview: PreviewMode,
) -> Result<ExitStatus> {
Expand Down Expand Up @@ -92,6 +93,7 @@ pub(crate) async fn venv(
no_project,
cache,
printer,
activatable,
relocatable,
preview,
)
Expand Down Expand Up @@ -151,6 +153,7 @@ async fn venv_impl(
no_project: bool,
cache: &Cache,
printer: Printer,
activatable: bool,
relocatable: bool,
preview: PreviewMode,
) -> miette::Result<ExitStatus> {
Expand Down Expand Up @@ -259,6 +262,7 @@ async fn venv_impl(
prompt,
system_site_packages,
allow_existing,
activatable,
relocatable,
seed,
)
Expand Down Expand Up @@ -372,33 +376,35 @@ async fn venv_impl(
.into_diagnostic()?;
}

// Determine the appropriate activation command.
let activation = match Shell::from_env() {
None => None,
Some(Shell::Bash | Shell::Zsh | Shell::Ksh) => Some(format!(
"source {}",
shlex_posix(venv.scripts().join("activate"))
)),
Some(Shell::Fish) => Some(format!(
"source {}",
shlex_posix(venv.scripts().join("activate.fish"))
)),
Some(Shell::Nushell) => Some(format!(
"overlay use {}",
shlex_posix(venv.scripts().join("activate.nu"))
)),
Some(Shell::Csh) => Some(format!(
"source {}",
shlex_posix(venv.scripts().join("activate.csh"))
)),
Some(Shell::Powershell) => Some(shlex_windows(
venv.scripts().join("activate"),
Shell::Powershell,
)),
Some(Shell::Cmd) => Some(shlex_windows(venv.scripts().join("activate"), Shell::Cmd)),
};
if let Some(act) = activation {
writeln!(printer.stderr(), "Activate with: {}", act.green()).into_diagnostic()?;
if activatable {
// Determine the appropriate activation command.
let activation = match Shell::from_env() {
None => None,
Some(Shell::Bash | Shell::Zsh | Shell::Ksh) => Some(format!(
"source {}",
shlex_posix(venv.scripts().join("activate"))
)),
Some(Shell::Fish) => Some(format!(
"source {}",
shlex_posix(venv.scripts().join("activate.fish"))
)),
Some(Shell::Nushell) => Some(format!(
"overlay use {}",
shlex_posix(venv.scripts().join("activate.nu"))
)),
Some(Shell::Csh) => Some(format!(
"source {}",
shlex_posix(venv.scripts().join("activate.csh"))
)),
Some(Shell::Powershell) => Some(shlex_windows(
venv.scripts().join("activate"),
Shell::Powershell,
)),
Some(Shell::Cmd) => Some(shlex_windows(venv.scripts().join("activate"), Shell::Cmd)),
};
if let Some(act) = activation {
writeln!(printer.stderr(), "Activate with: {}", act.green()).into_diagnostic()?;
}
}

Ok(ExitStatus::Success)
Expand Down
1 change: 1 addition & 0 deletions crates/uv/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
args.no_project,
&cache,
printer,
args.activatable,
args.relocatable,
globals.preview,
)
Expand Down
4 changes: 4 additions & 0 deletions crates/uv/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2135,6 +2135,7 @@ pub(crate) struct VenvSettings {
pub(crate) path: Option<PathBuf>,
pub(crate) prompt: Option<String>,
pub(crate) system_site_packages: bool,
pub(crate) activatable: bool,
pub(crate) relocatable: bool,
pub(crate) no_project: bool,
pub(crate) settings: PipSettings,
Expand All @@ -2152,6 +2153,8 @@ impl VenvSettings {
path,
prompt,
system_site_packages,
activatable,
not_activatable,
relocatable,
index_args,
index_strategy,
Expand All @@ -2169,6 +2172,7 @@ impl VenvSettings {
prompt,
system_site_packages,
no_project,
activatable: flag(activatable, not_activatable).unwrap_or(true),
relocatable,
settings: PipSettings::combine(
PipOptions {
Expand Down
6 changes: 5 additions & 1 deletion docs/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -7688,7 +7688,7 @@ If in a project, the default environment name can be changed with the `UV_PROJEC

If a virtual environment exists at the target path, it will be removed and a new, empty virtual environment will be created.

When using uv, the virtual environment does not need to be activated. uv will find a virtual environment (named `.venv`) in the working directory or any parent directories.
When using uv, the virtual environment does not need to be activated. uv will find a virtual environment (named `.venv`) in the working directory or any parent directories. See `--not-activatable` if you wish to disable the creation of activation scripts entirely.

<h3 class="cli-reference">Usage</h3>

Expand Down Expand Up @@ -7869,6 +7869,10 @@ uv venv [OPTIONS] [PATH]

</dd><dt><code>--no-python-downloads</code></dt><dd><p>Disable automatic downloads of Python.</p>

</dd><dt><code>--not-activatable</code></dt><dd><p>Disable the creation of activation scripts in the environment.</p>

<p>By default, uv will include activation scripts in the environment. When using <code>uv run</code>, these are often not required and can be skipped with <code>--not-activatable</code>.</p>

</dd><dt><code>--offline</code></dt><dd><p>Disable network access.</p>

<p>When disabled, uv will only use locally cached data and locally available files.</p>
Expand Down
Loading