Skip to content
Merged
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: 2 additions & 0 deletions .python-versions
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@
3.9.12
# The following is needed for `==3.13` request tests
3.13.0
# A pre-release version required for testing
3.14.0rc2
18 changes: 16 additions & 2 deletions crates/uv-python/src/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,7 @@ fn python_interpreters<'a>(
cache: &'a Cache,
preview: Preview,
) -> impl Iterator<Item = Result<(PythonSource, Interpreter), Error>> + 'a {
python_interpreters_from_executables(
let interpreters = python_interpreters_from_executables(
// Perform filtering on the discovered executables based on their source. This avoids
// unnecessary interpreter queries, which are generally expensive. We'll filter again
// with `interpreter_satisfies_environment_preference` after querying.
Expand Down Expand Up @@ -761,7 +761,21 @@ fn python_interpreters<'a>(
})
.filter_ok(move |(source, interpreter)| {
satisfies_python_preference(*source, interpreter, preference)
})
});

if std::env::var(uv_static::EnvVars::UV_INTERNAL__TEST_PYTHON_MANAGED).is_ok() {
Either::Left(interpreters.map_ok(|(source, interpreter)| {
// In test mode, change the source to `Managed` if a version was marked as such via
// `TestContext::with_versions_as_managed`.
if interpreter.is_managed() {
(PythonSource::Managed, interpreter)
} else {
(source, interpreter)
}
}))
} else {
Either::Right(interpreters)
}
}

/// Lazily convert Python executables into interpreters.
Expand Down
10 changes: 5 additions & 5 deletions crates/uv/src/commands/project/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2434,7 +2434,7 @@ pub(crate) async fn init_script_python_requirement(
) -> anyhow::Result<RequiresPython> {
let python_request = if let Some(request) = python {
// (1) Explicit request from user
PythonRequest::parse(request)
Some(PythonRequest::parse(request))
} else if let (false, Some(request)) = (
no_pin_python,
PythonVersionFile::discover(
Expand All @@ -2445,14 +2445,14 @@ pub(crate) async fn init_script_python_requirement(
.and_then(PythonVersionFile::into_version),
) {
// (2) Request from `.python-version`
request
Some(request)
} else {
// (3) Assume any Python version
PythonRequest::Any
// (3) No explicit request
None
};

let interpreter = PythonInstallation::find_or_download(
Some(&python_request),
python_request.as_ref(),
EnvironmentPreference::Any,
python_preference,
python_downloads,
Expand Down
43 changes: 43 additions & 0 deletions crates/uv/tests/it/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,49 @@ fn init_script_shebang() -> Result<()> {
Ok(())
}

// Make sure that `uv init --script` picks the latest non-pre-release version of Python
// for the `requires-python` constraint.
#[cfg(feature = "python-patch")]
#[test]
fn init_script_picks_latest_stable_version() -> Result<()> {
let managed_versions = &["3.14.0rc2", "3.13", "3.12"];
// If we do not mark these versions as managed, they would have `PythonSource::SearchPath(First)`, which
// would mean that pre-releases would be preferred without opt-in (see `PythonSource::allows_prereleases`).
let context =
TestContext::new_with_versions(managed_versions).with_versions_as_managed(managed_versions);

let script_path = context.temp_dir.join("main.py");

uv_snapshot!(context.filters(), context.init().arg("--script").arg("main.py"), @r#"
success: true
exit_code: 0
----- stdout -----

----- stderr -----
Initialized script at `main.py`
"#);

let resulting_script = fs_err::read_to_string(&script_path)?;
assert_snapshot!(
resulting_script, @r#"
# /// script
# requires-python = ">=3.13"
# dependencies = []
# ///


def main() -> None:
print("Hello from main.py!")


if __name__ == "__main__":
main()
"#
);

Ok(())
}

/// Run `uv init --lib` with an existing py.typed file
#[test]
fn init_py_typed_exists() -> Result<()> {
Expand Down
2 changes: 1 addition & 1 deletion crates/uv/tests/it/pip_install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12035,7 +12035,7 @@ fn install_python_preference() {
----- stdout -----

----- stderr -----
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
Using CPython 3.12.[X]
Creating virtual environment at: .venv
Activate with: source .venv/[BIN]/activate
");
Expand Down
4 changes: 2 additions & 2 deletions crates/uv/tests/it/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12644,7 +12644,7 @@ fn sync_python_preference() -> Result<()> {
----- stdout -----

----- stderr -----
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
Using CPython 3.12.[X]
Removed virtual environment at: .venv
Creating virtual environment at: .venv
Resolved 1 package in [TIME]
Expand Down Expand Up @@ -12698,7 +12698,7 @@ fn sync_python_preference() -> Result<()> {
----- stdout -----

----- stderr -----
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
Using CPython 3.12.[X]
Removed virtual environment at: .venv
Creating virtual environment at: .venv
Resolved 1 package in [TIME]
Expand Down
6 changes: 3 additions & 3 deletions crates/uv/tests/it/venv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1359,7 +1359,7 @@ fn venv_python_preference() {
----- stdout -----

----- stderr -----
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
Using CPython 3.12.[X]
Creating virtual environment at: .venv
Activate with: source .venv/[BIN]/activate
");
Expand Down Expand Up @@ -1394,7 +1394,7 @@ fn venv_python_preference() {
----- stdout -----

----- stderr -----
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
Using CPython 3.12.[X]
Creating virtual environment at: .venv
warning: A virtual environment already exists at `.venv`. In the future, uv will require `--clear` to replace it
Activate with: source .venv/[BIN]/activate
Expand All @@ -1406,7 +1406,7 @@ fn venv_python_preference() {
----- stdout -----

----- stderr -----
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
Using CPython 3.12.[X]
Creating virtual environment at: .venv
warning: A virtual environment already exists at `.venv`. In the future, uv will require `--clear` to replace it
Activate with: source .venv/[BIN]/activate
Expand Down
Loading