mirror of https://github.com/astral-sh/uv
Respect `.python-version` in `--isolated` runs (#5741)
Closes https://github.com/astral-sh/uv/issues/5740.
This commit is contained in:
parent
b26794bf6f
commit
030d477653
|
|
@ -154,17 +154,23 @@ pub(crate) enum FoundInterpreter {
|
||||||
Environment(PythonEnvironment),
|
Environment(PythonEnvironment),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FoundInterpreter {
|
/// The resolved Python request and requirement for a [`Workspace`].
|
||||||
/// Discover the interpreter to use in the current [`Workspace`].
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) async fn discover(
|
pub(crate) struct WorkspacePython {
|
||||||
workspace: &Workspace,
|
/// The resolved Python request, computed by considering (1) any explicit request from the user
|
||||||
|
/// via `--python`, (2) any implicit request from the user via `.python-version`, and (3) any
|
||||||
|
/// `Requires-Python` specifier in the `pyproject.toml`.
|
||||||
|
python_request: Option<PythonRequest>,
|
||||||
|
/// The resolved Python requirement for the project, computed by taking the intersection of all
|
||||||
|
/// `Requires-Python` specifiers in the workspace.
|
||||||
|
requires_python: Option<RequiresPython>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WorkspacePython {
|
||||||
|
/// Determine the [`WorkspacePython`] for the current [`Workspace`].
|
||||||
|
pub(crate) async fn from_request(
|
||||||
python_request: Option<PythonRequest>,
|
python_request: Option<PythonRequest>,
|
||||||
python_preference: PythonPreference,
|
workspace: &Workspace,
|
||||||
python_fetch: PythonFetch,
|
|
||||||
connectivity: Connectivity,
|
|
||||||
native_tls: bool,
|
|
||||||
cache: &Cache,
|
|
||||||
printer: Printer,
|
|
||||||
) -> Result<Self, ProjectError> {
|
) -> Result<Self, ProjectError> {
|
||||||
let requires_python = find_requires_python(workspace)?;
|
let requires_python = find_requires_python(workspace)?;
|
||||||
|
|
||||||
|
|
@ -182,6 +188,31 @@ impl FoundInterpreter {
|
||||||
.map(|specifiers| PythonRequest::Version(VersionRequest::Range(specifiers.clone())))
|
.map(|specifiers| PythonRequest::Version(VersionRequest::Range(specifiers.clone())))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
python_request,
|
||||||
|
requires_python,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FoundInterpreter {
|
||||||
|
/// Discover the interpreter to use in the current [`Workspace`].
|
||||||
|
pub(crate) async fn discover(
|
||||||
|
workspace: &Workspace,
|
||||||
|
python_request: Option<PythonRequest>,
|
||||||
|
python_preference: PythonPreference,
|
||||||
|
python_fetch: PythonFetch,
|
||||||
|
connectivity: Connectivity,
|
||||||
|
native_tls: bool,
|
||||||
|
cache: &Cache,
|
||||||
|
printer: Printer,
|
||||||
|
) -> Result<Self, ProjectError> {
|
||||||
|
// Resolve the Python request and requirement for the workspace.
|
||||||
|
let WorkspacePython {
|
||||||
|
python_request,
|
||||||
|
requires_python,
|
||||||
|
} = WorkspacePython::from_request(python_request, workspace).await?;
|
||||||
|
|
||||||
// Read from the virtual environment first.
|
// Read from the virtual environment first.
|
||||||
match find_environment(workspace, cache) {
|
match find_environment(workspace, cache) {
|
||||||
Ok(venv) => {
|
Ok(venv) => {
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ use uv_workspace::{DiscoveryOptions, VirtualProject, Workspace, WorkspaceError};
|
||||||
|
|
||||||
use crate::commands::pip::operations::Modifications;
|
use crate::commands::pip::operations::Modifications;
|
||||||
use crate::commands::project::environment::CachedEnvironment;
|
use crate::commands::project::environment::CachedEnvironment;
|
||||||
use crate::commands::project::ProjectError;
|
use crate::commands::project::{ProjectError, WorkspacePython};
|
||||||
use crate::commands::reporters::PythonDownloadReporter;
|
use crate::commands::reporters::PythonDownloadReporter;
|
||||||
use crate::commands::{pip, project, ExitStatus, SharedState};
|
use crate::commands::{pip, project, ExitStatus, SharedState};
|
||||||
use crate::printer::Printer;
|
use crate::printer::Printer;
|
||||||
|
|
@ -206,9 +206,16 @@ pub(crate) async fn run(
|
||||||
.connectivity(connectivity)
|
.connectivity(connectivity)
|
||||||
.native_tls(native_tls);
|
.native_tls(native_tls);
|
||||||
|
|
||||||
// Note we force preview on during `uv run` for now since the entire interface is in preview
|
// Resolve the Python request and requirement for the workspace.
|
||||||
PythonInstallation::find_or_fetch(
|
let WorkspacePython { python_request, .. } = WorkspacePython::from_request(
|
||||||
python.as_deref().map(PythonRequest::parse),
|
python.as_deref().map(PythonRequest::parse),
|
||||||
|
project.workspace(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Note we force preview on during `uv run` for now since the entire interface is in preview.
|
||||||
|
PythonInstallation::find_or_fetch(
|
||||||
|
python_request,
|
||||||
EnvironmentPreference::Any,
|
EnvironmentPreference::Any,
|
||||||
python_preference,
|
python_preference,
|
||||||
python_fetch,
|
python_fetch,
|
||||||
|
|
|
||||||
|
|
@ -915,3 +915,102 @@ fn run_without_output() -> Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ensure that we can import from the root project when layering `--with` requirements.
|
||||||
|
#[test]
|
||||||
|
fn run_isolated_python_version() -> Result<()> {
|
||||||
|
let context = TestContext::new_with_versions(&["3.8", "3.12"]);
|
||||||
|
|
||||||
|
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||||
|
pyproject_toml.write_str(indoc! { r#"
|
||||||
|
[build-system]
|
||||||
|
requires = ["hatchling"]
|
||||||
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "foo"
|
||||||
|
version = "1.0.0"
|
||||||
|
requires-python = ">=3.8"
|
||||||
|
dependencies = ["anyio"]
|
||||||
|
"#
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let src = context.temp_dir.child("src").child("foo");
|
||||||
|
src.create_dir_all()?;
|
||||||
|
|
||||||
|
let init = src.child("__init__.py");
|
||||||
|
init.touch()?;
|
||||||
|
|
||||||
|
let main = context.temp_dir.child("main.py");
|
||||||
|
main.write_str(indoc! { r"
|
||||||
|
import sys
|
||||||
|
|
||||||
|
print((sys.version_info.major, sys.version_info.minor))
|
||||||
|
"
|
||||||
|
})?;
|
||||||
|
|
||||||
|
uv_snapshot!(context.filters(), context.run().arg("main.py"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
(3, 8)
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
warning: `uv run` is experimental and may change without warning
|
||||||
|
Using Python 3.8.[X] interpreter at: [PYTHON-3.8]
|
||||||
|
Creating virtualenv at: .venv
|
||||||
|
Resolved 6 packages in [TIME]
|
||||||
|
Prepared 6 packages in [TIME]
|
||||||
|
Installed 6 packages in [TIME]
|
||||||
|
+ anyio==4.3.0
|
||||||
|
+ exceptiongroup==1.2.0
|
||||||
|
+ foo==1.0.0 (from file://[TEMP_DIR]/)
|
||||||
|
+ idna==3.6
|
||||||
|
+ sniffio==1.3.1
|
||||||
|
+ typing-extensions==4.10.0
|
||||||
|
"###);
|
||||||
|
|
||||||
|
uv_snapshot!(context.filters(), context.run().arg("--isolated").arg("main.py"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
(3, 8)
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
warning: `uv run` is experimental and may change without warning
|
||||||
|
Resolved 6 packages in [TIME]
|
||||||
|
Prepared 5 packages in [TIME]
|
||||||
|
Installed 6 packages in [TIME]
|
||||||
|
+ anyio==4.3.0
|
||||||
|
+ exceptiongroup==1.2.0
|
||||||
|
+ foo==1.0.0 (from file://[TEMP_DIR]/)
|
||||||
|
+ idna==3.6
|
||||||
|
+ sniffio==1.3.1
|
||||||
|
+ typing-extensions==4.10.0
|
||||||
|
"###);
|
||||||
|
|
||||||
|
// Set the `.python-version` to `3.12`.
|
||||||
|
context
|
||||||
|
.temp_dir
|
||||||
|
.child(PYTHON_VERSION_FILENAME)
|
||||||
|
.write_str("3.12")?;
|
||||||
|
|
||||||
|
uv_snapshot!(context.filters(), context.run().arg("--isolated").arg("main.py"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
(3, 12)
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
warning: `uv run` is experimental and may change without warning
|
||||||
|
Resolved 6 packages in [TIME]
|
||||||
|
Prepared 3 packages in [TIME]
|
||||||
|
Installed 4 packages in [TIME]
|
||||||
|
+ anyio==4.3.0
|
||||||
|
+ foo==1.0.0 (from file://[TEMP_DIR]/)
|
||||||
|
+ idna==3.6
|
||||||
|
+ sniffio==1.3.1
|
||||||
|
"###);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue