Skip to content

Commit

Permalink
Add support for global, non venv Python invocations
Browse files Browse the repository at this point in the history
  • Loading branch information
mitsuhiko committed Jun 20, 2023
1 parent b52aa64 commit 7e7edaf
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 4 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ that were not yet released.

_Unreleased_

<!-- released start -->
- Added support for the new `behavior.global-python` flag which turns on global
Python shimming. When enabled then the `python` shim works even outside of
Rye managed projects. Additionally the shim (when run outside of Rye managed
projects) supports a special first paramter `+VERSION` which requests a
specific version of Python (eg: `python +3.8` to request Python 3.8). #336

## 0.8.0

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.

3 changes: 3 additions & 0 deletions docs/guide/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ https = "http://127.0.0.1:4000"
# When set to true the `managed` flag is always assumed to be true.
force_rye_managed = false

# Enables global shims when set to `true`
global-python = false

# a array of tables with optional sources. Same format as in pyproject.toml
[[sources]]
name = "default"
Expand Down
49 changes: 47 additions & 2 deletions rye/src/cli/shim.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
use std::convert::Infallible;
use std::env;
use std::ffi::{OsStr, OsString};
use std::str::FromStr;

use anyhow::{bail, Context, Error};
use anyhow::{anyhow, bail, Context, Error};
use same_file::is_same_file;
use std::process::Command;
use which::which_in_global;

use crate::bootstrap::{ensure_self_venv, get_pip_runner};
use crate::config::Config;
use crate::consts::VENV_BIN;
use crate::pyproject::PyProject;
use crate::platform::{get_python_version_request_from_pyenv_pin, get_toolchain_python_bin};
use crate::pyproject::{latest_available_python_version, PyProject};
use crate::sources::{PythonVersion, PythonVersionRequest};
use crate::sync::{sync, SyncOptions};
use crate::utils::{exec_spawn, get_venv_python_bin, CommandOutput};

Expand Down Expand Up @@ -101,6 +105,47 @@ fn get_shim_target(target: &str, args: &[OsString]) -> Result<Option<Vec<OsStrin
if target == "pip" || target == "pip3" {
return Ok(Some(get_pip_shim(&pyproject, args, CommandOutput::Normal)?));
}
} else if target == "python" || target == "python3" {
let config = Config::current();
if config.global_python() {
let mut args = args.to_vec();
let mut remove1 = false;

let version_request = if let Some(rest) = args
.get(1)
.and_then(|x| x.as_os_str().to_str())
.and_then(|x| x.strip_prefix('+'))
{
remove1 = true;
PythonVersionRequest::from_str(rest)
.context("invalid python version requested from command line")?
} else {
match get_python_version_request_from_pyenv_pin(&std::env::current_exe()?) {
Some(version_request) => version_request,
None => config.default_toolchain()?,
}
};

let py_ver = match PythonVersion::try_from(version_request.clone()) {
Ok(py_ver) => py_ver,
Err(_) => latest_available_python_version(&version_request)
.ok_or_else(|| anyhow!("Unable to determine target Python version"))?,
};
let py = get_toolchain_python_bin(&py_ver)?;
if !py.is_file() {
bail!(
"Requested Python version ({}) is not installed. Install with `rye fetch {}`",
py_ver,
py_ver
);
}

args[0] = py.into();
if remove1 {
args.remove(1);
}
return Ok(Some(args));
}
}

// if we make it this far, we did not find a shim in the project, look for
Expand Down
9 changes: 9 additions & 0 deletions rye/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,15 @@ impl Config {
})
}

/// Allow rye shims to resolve globally installed Pythons.
pub fn global_python(&self) -> bool {
self.doc
.get("behavior")
.and_then(|x| x.get("global-python"))
.and_then(|x| x.as_bool())
.unwrap_or(false)
}

/// Pretend that all projects are rye managed.
pub fn force_rye_managed(&self) -> bool {
self.doc
Expand Down

0 comments on commit 7e7edaf

Please sign in to comment.