diff --git a/rye/src/bootstrap.rs b/rye/src/bootstrap.rs index ecde15da95..ea27e17146 100644 --- a/rye/src/bootstrap.rs +++ b/rye/src/bootstrap.rs @@ -17,7 +17,7 @@ use crate::platform::{ get_app_dir, get_canonical_py_path, get_python_bin_within, get_toolchain_python_bin, list_known_toolchains, }; -use crate::pyproject::latest_available_python_version; +use crate::pyproject::{latest_available_python_version, PyProject}; use crate::sources::py::{get_download_url, PythonVersion, PythonVersionRequest}; use crate::utils::{check_checksum, symlink_file, unpack_archive, CommandOutput, IoPathContext}; use crate::uv::UvBuilder; @@ -143,6 +143,8 @@ pub fn ensure_self_venv_with_toolchain( let py_bin = get_toolchain_python_bin(&version)?; + let pyproject = PyProject::discover()?; + // linux specific detection of shared libraries. #[cfg(target_os = "linux")] { @@ -151,7 +153,13 @@ pub fn ensure_self_venv_with_toolchain( // initialize the virtualenv { - let uv_venv = uv.venv(&venv_dir, &py_bin, &version, None)?; + let uv_venv = uv.venv( + &venv_dir, + &py_bin, + &version, + None, + pyproject.system_site_packages(), + )?; // write our marker uv_venv.write_marker()?; // update pip and our requirements diff --git a/rye/src/cli/add.rs b/rye/src/cli/add.rs index 9fa56f2ad2..f4861628c0 100644 --- a/rye/src/cli/add.rs +++ b/rye/src/cli/add.rs @@ -476,12 +476,19 @@ fn resolve_requirements_with_uv( let venv_path = pyproject_toml.venv_path(); let py_bin = get_venv_python_bin(&venv_path); let sources = ExpandedSources::from_sources(&pyproject_toml.sources()?)?; + let pyproject = PyProject::discover()?; let uv = UvBuilder::new() .with_output(output.quieter()) .with_sources(sources) .ensure_exists()? - .venv(&venv_path, &py_bin, py_ver, None)?; + .venv( + &venv_path, + &py_bin, + py_ver, + None, + pyproject.system_site_packages(), + )?; for req in requirements { let mut new_req = uv.resolve( diff --git a/rye/src/cli/list.rs b/rye/src/cli/list.rs index 1620b1e289..86d7d1a110 100644 --- a/rye/src/cli/list.rs +++ b/rye/src/cli/list.rs @@ -39,6 +39,7 @@ pub fn execute(cmd: Args) -> Result<(), Error> { &python, &project.venv_python_version()?, None, + project.system_site_packages(), )? .freeze()?; } diff --git a/rye/src/installer.rs b/rye/src/installer.rs index d93adda388..dce3340b9d 100644 --- a/rye/src/installer.rs +++ b/rye/src/installer.rs @@ -139,14 +139,15 @@ pub fn install( &py_ver, &target_venv_path, requirement.name.as_str(), + false, )?; - if Config::current().use_uv() { + if config.use_uv() { let result = UvBuilder::new() .with_output(output.quieter()) .with_sources(sources) .ensure_exists()? - .venv(&target_venv_path, &py, &py_ver, None)? + .venv(&target_venv_path, &py, &py_ver, None, false)? .with_output(output) .install( &requirement, diff --git a/rye/src/piptools.rs b/rye/src/piptools.rs index 7764aba168..d50d4cbe7c 100644 --- a/rye/src/piptools.rs +++ b/rye/src/piptools.rs @@ -55,7 +55,7 @@ fn get_pip_tools_bin(py_ver: &PythonVersion, output: CommandOutput) -> Result bool { lock_with_sources(&self.doc) } + + /// Include system site packages when creating virtualenvs? + pub fn system_site_packages(&self) -> bool { + system_site_packages(&self.doc) + } } /// Check if recurse should be skipped into directory with this name @@ -1014,6 +1019,14 @@ impl PyProject { } } + /// Include system site packages when creating virtualenvs? + pub fn system_site_packages(&self) -> bool { + match self.workspace { + Some(ref workspace) => workspace.system_site_packages(), + None => system_site_packages(&self.doc), + } + } + /// Save back changes pub fn save(&self) -> Result<(), Error> { let path = self.toml_path(); @@ -1288,6 +1301,14 @@ fn lock_with_sources(doc: &DocumentMut) -> bool { .unwrap_or(false) } +fn system_site_packages(doc: &DocumentMut) -> bool { + doc.get("tool") + .and_then(|x| x.get("rye")) + .and_then(|x| x.get("system-site-packages")) + .and_then(|x| x.as_bool()) + .unwrap_or(false) +} + fn get_project_metadata(path: &Path) -> Result { let self_venv = ensure_self_venv(CommandOutput::Normal)?; let mut metadata = Command::new(self_venv.join(VENV_BIN).join("python")); diff --git a/rye/src/sync.rs b/rye/src/sync.rs index 5ab816a616..2a6e585441 100644 --- a/rye/src/sync.rs +++ b/rye/src/sync.rs @@ -171,8 +171,15 @@ pub fn sync(mut cmd: SyncOptions) -> Result<(), Error> { ); echo!(if output, "Python version: {}", style(&py_ver).cyan()); let prompt = pyproject.name().unwrap_or("venv"); - create_virtualenv(output, &self_venv, &py_ver, &venv, prompt) - .context("failed creating virtualenv ahead of sync")?; + create_virtualenv( + output, + &self_venv, + &py_ver, + &venv, + prompt, + pyproject.system_site_packages(), + ) + .context("failed creating virtualenv ahead of sync")?; } // prepare necessary utilities for pip-sync. This is a super crude @@ -257,7 +264,13 @@ pub fn sync(mut cmd: SyncOptions) -> Result<(), Error> { .with_workdir(&pyproject.workspace_path()) .with_sources(sources) .ensure_exists()? - .venv(&venv, &py_path, &py_ver, None)? + .venv( + &venv, + &py_path, + &py_ver, + None, + pyproject.system_site_packages(), + )? .with_output(output) .sync(&target_lockfile)?; } else { @@ -347,6 +360,7 @@ pub fn create_virtualenv( py_ver: &PythonVersion, venv: &Path, prompt: &str, + system_site_packages: bool, ) -> Result<(), Error> { let py_bin = get_toolchain_python_bin(py_ver)?; @@ -356,7 +370,7 @@ pub fn create_virtualenv( let uv = UvBuilder::new() .with_output(output.quieter()) .ensure_exists()? - .venv(venv, &py_bin, py_ver, Some(prompt)) + .venv(venv, &py_bin, py_ver, Some(prompt), system_site_packages) .context("failed to initialize virtualenv")?; uv.write_marker()?; uv.sync_marker(); diff --git a/rye/src/uv.rs b/rye/src/uv.rs index 9dbf87db42..52574a1bd1 100644 --- a/rye/src/uv.rs +++ b/rye/src/uv.rs @@ -278,12 +278,13 @@ impl Uv { py_bin: &Path, version: &PythonVersion, prompt: Option<&str>, + system_site_packages: bool, ) -> Result { match read_venv_marker(venv_dir) { Some(venv) if venv.is_compatible(version) => { Ok(UvWithVenv::new(self.clone(), venv_dir, version)) } - _ => self.create_venv(venv_dir, py_bin, version, prompt), + _ => self.create_venv(venv_dir, py_bin, version, prompt, system_site_packages), } } @@ -300,12 +301,16 @@ impl Uv { py_bin: &Path, version: &PythonVersion, prompt: Option<&str>, + system_site_packages: bool, ) -> Result { let mut cmd = self.cmd(); cmd.arg("venv").arg("--python").arg(py_bin); if let Some(prompt) = prompt { cmd.arg("--prompt").arg(prompt); } + if system_site_packages { + cmd.arg("--system-site-packages"); + } cmd.arg(venv_dir); let status = cmd.status().with_context(|| { format!( diff --git a/rye/tests/test_sync.rs b/rye/tests/test_sync.rs index 7b3faa8bc3..e7f321f864 100644 --- a/rye/tests/test_sync.rs +++ b/rye/tests/test_sync.rs @@ -1,8 +1,8 @@ use std::fs; -use insta::{assert_snapshot, Settings}; - use crate::common::{rye_cmd_snapshot, Space}; +use insta::{assert_snapshot, Settings}; +use toml_edit::value; mod common; @@ -265,3 +265,18 @@ fn test_autosync_remember() { werkzeug==3.0.1 "###); } + +#[test] +fn test_sync_include_system_site_packages() { + let space = Space::new(); + space.init("my-project"); + space.edit_toml("pyproject.toml", |doc| { + doc["tool"]["rye"]["system-site-packages"] = value(true); + }); + + space.rye_cmd().arg("sync").status().expect("ok"); + + assert!(fs::read_to_string(space.venv_path().join("pyvenv.cfg")) + .unwrap() + .contains("include-system-site-packages = true")); +}