Update activation scripts from virtualenv (#3376)

## Summary

Refreshes some of the activation scripts, and fixes some bugs in
`activate_this.py` that were likely the rest of some erroneous
copy-pasting.

Closes https://github.com/astral-sh/uv/issues/3346.

## Test Plan

```
❯ python
Python 3.12.0 (main, Feb 28 2024, 09:44:16) [Clang 15.0.0 (clang-1500.1.0.2.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import httpx
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'httpx'
>>> activator = '.venv/bin/activate_this.py'
>>> with open(activator) as f:
...     exec(f.read(), {'__file__': activator})
...
>>> import httpx
```
This commit is contained in:
Charlie Marsh 2024-05-04 19:30:00 -04:00 committed by GitHub
parent 2a212eb6a9
commit 37635fda56
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 30 additions and 17 deletions

1
Cargo.lock generated
View file

@ -5067,6 +5067,7 @@ dependencies = [
"clap",
"directories",
"fs-err",
"itertools 0.12.1",
"pathdiff",
"platform-tags",
"pypi-types",

View file

@ -32,6 +32,7 @@ anstream = { workspace = true }
clap = { workspace = true, features = ["derive"], optional = true }
directories = { workspace = true }
fs-err = { workspace = true }
itertools = { workspace = true }
pathdiff = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }

View file

@ -83,7 +83,7 @@ set -gx VIRTUAL_ENV '{{ VIRTUAL_ENV_DIR }}'
# https://github.com/fish-shell/fish-shell/issues/436 altered PATH handling
if test (echo $FISH_VERSION | head -c 1) -lt 3
set -gx _OLD_VIRTUAL_PATH (_bashify_path $PATH)
set -gx _OLD_VIRTUAL_PATH (_bashify_path $PATH)
else
set -gx _OLD_VIRTUAL_PATH $PATH
end

View file

@ -67,7 +67,7 @@ else {
New-Variable -Scope global -Name _OLD_VIRTUAL_PATH -Value $env:PATH
$env:PATH = "$env:VIRTUAL_ENV/{{ BIN_NAME }};" + $env:PATH
$env:PATH = "$env:VIRTUAL_ENV/{{ BIN_NAME }}{{ PATH_SEP }}" + $env:PATH
if (!$env:VIRTUAL_ENV_DISABLE_PROMPT) {
function global:_old_virtual_prompt {
""

View file

@ -26,6 +26,7 @@ Use exec(open(this_file).read(), {'__file__': this_file}).
This can be used when you must use an existing Python interpreter, not the virtualenv bin/python.
""" # noqa: D415
from __future__ import annotations
import os
@ -35,7 +36,7 @@ import sys
try:
abs_file = os.path.abspath(__file__)
except NameError as exc:
msg = "You must use exec(open(this_file).read(), {'__file__': this_file}))"
msg = "You must use exec(open(this_file).read(), {'__file__': this_file})"
raise AssertionError(msg) from exc
bin_dir = os.path.dirname(abs_file)
@ -44,13 +45,13 @@ base = bin_dir[: -len("{{ BIN_NAME }}") - 1] # strip away the bin part from the
# prepend bin to PATH (this file is inside the bin directory)
os.environ["PATH"] = os.pathsep.join([bin_dir, *os.environ.get("PATH", "").split(os.pathsep)])
os.environ["VIRTUAL_ENV"] = base # virtual env is right above bin directory
os.environ["VIRTUAL_ENV_PROMPT"] = "" or os.path.basename(base) # noqa: SIM222
os.environ["VIRTUAL_ENV_PROMPT"] = "{{ VIRTUAL_PROMPT }}" or os.path.basename(base) # noqa: SIM222
# add the virtual environments libraries to the host python import mechanism
prev_length = len(sys.path)
for lib in "{{ RELATIVE_SITE_PACKAGES }}".split(os.pathsep):
path = os.path.realpath(os.path.join(bin_dir, lib))
site.addsitedir(path.decode("utf-8") if "" else path)
site.addsitedir(path)
sys.path[:] = sys.path[prev_length:] + sys.path[0:prev_length]
sys.real_prefix = sys.prefix

View file

@ -1,4 +1,4 @@
//! Create a bare virtualenv without any packages install
//! Create a bare virtualenv without any packages installed.
use std::env;
use std::env::consts::EXE_SUFFIX;
@ -8,14 +8,16 @@ use std::path::Path;
use fs_err as fs;
use fs_err::File;
use pypi_types::Scheme;
use itertools::Itertools;
use tracing::info;
use crate::{Error, Prompt};
use pypi_types::Scheme;
use uv_fs::{cachedir, Simplified};
use uv_interpreter::{Interpreter, VirtualEnvironment};
use uv_version::version;
use crate::{Error, Prompt};
/// The bash activate scripts with the venv dependent paths patches out
const ACTIVATE_TEMPLATES: &[(&str, &str)] = &[
("activate", include_str!("activator/activate")),
@ -195,11 +197,21 @@ pub fn create_bare_venv(
// Add all the activate scripts for different shells
for (name, template) in ACTIVATE_TEMPLATES {
let relative_site_packages = pathdiff::diff_paths(
&interpreter.virtualenv().purelib,
&interpreter.virtualenv().scripts,
)
.expect("Failed to calculate relative path to site-packages");
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 activator = template
.replace(
"{{ VIRTUAL_ENV_DIR }}",
@ -211,10 +223,8 @@ pub fn create_bare_venv(
"{{ VIRTUAL_PROMPT }}",
prompt.as_deref().unwrap_or_default(),
)
.replace(
"{{ RELATIVE_SITE_PACKAGES }}",
relative_site_packages.simplified().to_str().unwrap(),
);
.replace("{{ PATH_SEP }}", path_sep)
.replace("{{ RELATIVE_SITE_PACKAGES }}", &relative_site_packages);
fs::write(scripts.join(name), activator)?;
}