mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-02 04:48:18 +00:00
Log Python choice in uv init (#16182)
Example output:
```
$ uv-debug init foo -v
DEBUG uv 0.9.0+6 (d3324baf68 2025-10-08)
DEBUG Acquired shared lock for `/home/konsti/.cache/uv`
DEBUG No Python version file found in ancestors of working directory: /home/konsti/projects/foo
DEBUG Checking for Python environment at: `foo/.venv`
DEBUG Searching for default Python interpreter in managed installations or search path
DEBUG Searching for managed installations at `/home/konsti/.local/share/uv/python`
DEBUG Found managed installation `cpython-3.14.0-linux-x86_64-gnu`
DEBUG Found `cpython-3.14.0-linux-x86_64-gnu` at `/home/konsti/.local/share/uv/python/cpython-3.14.0-linux-x86_64-gnu/bin/python3.14` (managed installations)
DEBUG Using Python version `>=3.14` from default interpreter
DEBUG `git rev-parse --is-inside-work-tree` failed but didn't contain `not a git repository` in stderr for `/home/konsti/projects/foo`
DEBUG No Python version file found in ancestors of working directory: /home/konsti/projects/foo
DEBUG Writing Python versions to `/home/konsti/projects/foo/.python-version`
Initialized project `foo` at `/home/konsti/projects/foo`
DEBUG Released lock at `/home/konsti/.cache/uv/.lock`
```
First commit is refactoring, second commit is the actual change.
This commit is contained in:
parent
c96abc93f2
commit
40397ddb4b
1 changed files with 244 additions and 208 deletions
|
|
@ -365,212 +365,20 @@ async fn init_project(
|
|||
None
|
||||
};
|
||||
|
||||
// Add a `requires-python` field to the `pyproject.toml` and return the corresponding interpreter.
|
||||
let (requires_python, python_request) = if let Some(python_request) = python_request {
|
||||
// (1) A request from the user or `.python-version` file
|
||||
// This can be arbitrary, i.e., not a version — in which case we may need to resolve the
|
||||
// interpreter
|
||||
match python_request {
|
||||
PythonRequest::Version(VersionRequest::MajorMinor(major, minor, variant)) => {
|
||||
let requires_python = RequiresPython::greater_than_equal_version(&Version::new([
|
||||
u64::from(major),
|
||||
u64::from(minor),
|
||||
]));
|
||||
|
||||
let python_request = if pin_python {
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinor(
|
||||
major, minor, variant,
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
(requires_python, python_request)
|
||||
}
|
||||
PythonRequest::Version(VersionRequest::MajorMinorPatch(
|
||||
major,
|
||||
minor,
|
||||
patch,
|
||||
variant,
|
||||
)) => {
|
||||
let requires_python = RequiresPython::greater_than_equal_version(&Version::new([
|
||||
u64::from(major),
|
||||
u64::from(minor),
|
||||
u64::from(patch),
|
||||
]));
|
||||
|
||||
let python_request = if pin_python {
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinorPatch(
|
||||
major, minor, patch, variant,
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
(requires_python, python_request)
|
||||
}
|
||||
ref python_request @ PythonRequest::Version(VersionRequest::Range(
|
||||
ref specifiers,
|
||||
variant,
|
||||
)) => {
|
||||
let requires_python = RequiresPython::from_specifiers(specifiers);
|
||||
|
||||
let python_request = if pin_python {
|
||||
let interpreter = PythonInstallation::find_or_download(
|
||||
Some(python_request),
|
||||
EnvironmentPreference::OnlySystem,
|
||||
python_preference,
|
||||
python_downloads,
|
||||
client_builder,
|
||||
cache,
|
||||
Some(&reporter),
|
||||
install_mirrors.python_install_mirror.as_deref(),
|
||||
install_mirrors.pypy_install_mirror.as_deref(),
|
||||
install_mirrors.python_downloads_json_url.as_deref(),
|
||||
preview,
|
||||
)
|
||||
.await?
|
||||
.into_interpreter();
|
||||
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinor(
|
||||
interpreter.python_major(),
|
||||
interpreter.python_minor(),
|
||||
variant,
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
(requires_python, python_request)
|
||||
}
|
||||
python_request => {
|
||||
let interpreter = PythonInstallation::find_or_download(
|
||||
Some(&python_request),
|
||||
EnvironmentPreference::OnlySystem,
|
||||
python_preference,
|
||||
python_downloads,
|
||||
client_builder,
|
||||
cache,
|
||||
Some(&reporter),
|
||||
install_mirrors.python_install_mirror.as_deref(),
|
||||
install_mirrors.pypy_install_mirror.as_deref(),
|
||||
install_mirrors.python_downloads_json_url.as_deref(),
|
||||
preview,
|
||||
)
|
||||
.await?
|
||||
.into_interpreter();
|
||||
|
||||
let requires_python =
|
||||
RequiresPython::greater_than_equal_version(&interpreter.python_minor_version());
|
||||
|
||||
let python_request = if pin_python {
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinor(
|
||||
interpreter.python_major(),
|
||||
interpreter.python_minor(),
|
||||
PythonVariant::Default,
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
(requires_python, python_request)
|
||||
}
|
||||
}
|
||||
} else if let Ok(virtualenv) = PythonEnvironment::from_root(path.join(".venv"), cache) {
|
||||
// (2) An existing Python environment in the target directory
|
||||
debug!("Using Python version from existing virtual environment in project");
|
||||
let interpreter = virtualenv.into_interpreter();
|
||||
|
||||
let requires_python =
|
||||
RequiresPython::greater_than_equal_version(&interpreter.python_minor_version());
|
||||
|
||||
// Pin to the minor version.
|
||||
let python_request = if pin_python {
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinor(
|
||||
interpreter.python_major(),
|
||||
interpreter.python_minor(),
|
||||
PythonVariant::Default,
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
(requires_python, python_request)
|
||||
} else if let Some(requires_python) = workspace
|
||||
.as_ref()
|
||||
.map(|workspace| find_requires_python(workspace, &DependencyGroupsWithDefaults::none()))
|
||||
.transpose()?
|
||||
.flatten()
|
||||
{
|
||||
// (3) `requires-python` from the workspace
|
||||
debug!("Using Python version from project workspace");
|
||||
let python_request = PythonRequest::Version(VersionRequest::Range(
|
||||
requires_python.specifiers().clone(),
|
||||
PythonVariant::Default,
|
||||
));
|
||||
|
||||
// Pin to the minor version.
|
||||
let python_request = if pin_python {
|
||||
let interpreter = PythonInstallation::find_or_download(
|
||||
Some(&python_request),
|
||||
EnvironmentPreference::OnlySystem,
|
||||
python_preference,
|
||||
python_downloads,
|
||||
client_builder,
|
||||
cache,
|
||||
Some(&reporter),
|
||||
install_mirrors.python_install_mirror.as_deref(),
|
||||
install_mirrors.pypy_install_mirror.as_deref(),
|
||||
install_mirrors.python_downloads_json_url.as_deref(),
|
||||
preview,
|
||||
)
|
||||
.await?
|
||||
.into_interpreter();
|
||||
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinor(
|
||||
interpreter.python_major(),
|
||||
interpreter.python_minor(),
|
||||
PythonVariant::Default,
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
(requires_python, python_request)
|
||||
} else {
|
||||
// (4) Default to the system Python
|
||||
let interpreter = PythonInstallation::find_or_download(
|
||||
None,
|
||||
EnvironmentPreference::OnlySystem,
|
||||
python_preference,
|
||||
python_downloads,
|
||||
client_builder,
|
||||
cache,
|
||||
Some(&reporter),
|
||||
install_mirrors.python_install_mirror.as_deref(),
|
||||
install_mirrors.pypy_install_mirror.as_deref(),
|
||||
install_mirrors.python_downloads_json_url.as_deref(),
|
||||
preview,
|
||||
)
|
||||
.await?
|
||||
.into_interpreter();
|
||||
|
||||
let requires_python =
|
||||
RequiresPython::greater_than_equal_version(&interpreter.python_minor_version());
|
||||
|
||||
// Pin to the minor version.
|
||||
let python_request = if pin_python {
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinor(
|
||||
interpreter.python_major(),
|
||||
interpreter.python_minor(),
|
||||
PythonVariant::Default,
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
(requires_python, python_request)
|
||||
};
|
||||
let (requires_python, python_pin) = determine_requires_python(
|
||||
path,
|
||||
pin_python,
|
||||
install_mirrors,
|
||||
client_builder,
|
||||
python_preference,
|
||||
python_downloads,
|
||||
cache,
|
||||
preview,
|
||||
workspace.as_ref(),
|
||||
&reporter,
|
||||
python_request,
|
||||
)
|
||||
.await?;
|
||||
|
||||
project_kind.init(
|
||||
name,
|
||||
|
|
@ -625,7 +433,7 @@ async fn init_project(
|
|||
)?;
|
||||
}
|
||||
// Write .python-version if it doesn't exist in the workspace or if the version differs
|
||||
if let Some(python_request) = python_request {
|
||||
if let Some(python_request) = python_pin {
|
||||
if PythonVersionFile::discover(path, &VersionFileDiscoveryOptions::default())
|
||||
.await?
|
||||
.filter(|file| {
|
||||
|
|
@ -645,7 +453,7 @@ async fn init_project(
|
|||
}
|
||||
} else {
|
||||
// Write .python-version if it doesn't exist in the project directory.
|
||||
if let Some(python_request) = python_request {
|
||||
if let Some(python_request) = python_pin {
|
||||
if PythonVersionFile::discover(path, &VersionFileDiscoveryOptions::default())
|
||||
.await?
|
||||
.filter(|file| file.version().is_some())
|
||||
|
|
@ -663,6 +471,234 @@ async fn init_project(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn determine_requires_python(
|
||||
path: &Path,
|
||||
pin_python: bool,
|
||||
install_mirrors: PythonInstallMirrors,
|
||||
client_builder: &BaseClientBuilder<'_>,
|
||||
python_preference: PythonPreference,
|
||||
python_downloads: PythonDownloads,
|
||||
cache: &Cache,
|
||||
preview: Preview,
|
||||
workspace: Option<&Workspace>,
|
||||
reporter: &PythonDownloadReporter,
|
||||
python_request: Option<PythonRequest>,
|
||||
) -> Result<(RequiresPython, Option<PythonRequest>)> {
|
||||
// Add a `requires-python` field to the `pyproject.toml` and return the corresponding interpreter.
|
||||
if let Some(python_request) = python_request {
|
||||
// (1) A request from the user or `.python-version` file
|
||||
// This can be arbitrary, i.e., not a version — in which case we may need to resolve the
|
||||
// interpreter
|
||||
let (requires_python, python_pin) = match &python_request {
|
||||
PythonRequest::Version(VersionRequest::MajorMinor(major, minor, variant)) => {
|
||||
let requires_python = RequiresPython::greater_than_equal_version(&Version::new([
|
||||
u64::from(*major),
|
||||
u64::from(*minor),
|
||||
]));
|
||||
|
||||
let python_pin = if pin_python {
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinor(
|
||||
*major, *minor, *variant,
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
(requires_python, python_pin)
|
||||
}
|
||||
PythonRequest::Version(VersionRequest::MajorMinorPatch(
|
||||
major,
|
||||
minor,
|
||||
patch,
|
||||
variant,
|
||||
)) => {
|
||||
let requires_python = RequiresPython::greater_than_equal_version(&Version::new([
|
||||
u64::from(*major),
|
||||
u64::from(*minor),
|
||||
u64::from(*patch),
|
||||
]));
|
||||
|
||||
let python_pin = if pin_python {
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinorPatch(
|
||||
*major, *minor, *patch, *variant,
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
(requires_python, python_pin)
|
||||
}
|
||||
python_request @ PythonRequest::Version(VersionRequest::Range(specifiers, variant)) => {
|
||||
let requires_python = RequiresPython::from_specifiers(specifiers);
|
||||
|
||||
let python_pin = if pin_python {
|
||||
let interpreter = PythonInstallation::find_or_download(
|
||||
Some(python_request),
|
||||
EnvironmentPreference::OnlySystem,
|
||||
python_preference,
|
||||
python_downloads,
|
||||
client_builder,
|
||||
cache,
|
||||
Some(reporter),
|
||||
install_mirrors.python_install_mirror.as_deref(),
|
||||
install_mirrors.pypy_install_mirror.as_deref(),
|
||||
install_mirrors.python_downloads_json_url.as_deref(),
|
||||
preview,
|
||||
)
|
||||
.await?
|
||||
.into_interpreter();
|
||||
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinor(
|
||||
interpreter.python_major(),
|
||||
interpreter.python_minor(),
|
||||
*variant,
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
(requires_python, python_pin)
|
||||
}
|
||||
python_request => {
|
||||
let interpreter = PythonInstallation::find_or_download(
|
||||
Some(python_request),
|
||||
EnvironmentPreference::OnlySystem,
|
||||
python_preference,
|
||||
python_downloads,
|
||||
client_builder,
|
||||
cache,
|
||||
Some(reporter),
|
||||
install_mirrors.python_install_mirror.as_deref(),
|
||||
install_mirrors.pypy_install_mirror.as_deref(),
|
||||
install_mirrors.python_downloads_json_url.as_deref(),
|
||||
preview,
|
||||
)
|
||||
.await?
|
||||
.into_interpreter();
|
||||
|
||||
let requires_python =
|
||||
RequiresPython::greater_than_equal_version(&interpreter.python_minor_version());
|
||||
|
||||
let python_pin = if pin_python {
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinor(
|
||||
interpreter.python_major(),
|
||||
interpreter.python_minor(),
|
||||
PythonVariant::Default,
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
(requires_python, python_pin)
|
||||
}
|
||||
};
|
||||
|
||||
debug!("Using Python version `{requires_python}` from request `{python_request}`");
|
||||
|
||||
Ok((requires_python, python_pin))
|
||||
} else if let Ok(virtualenv) = PythonEnvironment::from_root(path.join(".venv"), cache) {
|
||||
// (2) An existing Python environment in the target directory
|
||||
let interpreter = virtualenv.into_interpreter();
|
||||
|
||||
let requires_python =
|
||||
RequiresPython::greater_than_equal_version(&interpreter.python_minor_version());
|
||||
|
||||
// Pin to the minor version.
|
||||
let python_pin = if pin_python {
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinor(
|
||||
interpreter.python_major(),
|
||||
interpreter.python_minor(),
|
||||
PythonVariant::Default,
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
debug!(
|
||||
"Using Python version `{requires_python}` from existing virtual environment in project"
|
||||
);
|
||||
|
||||
Ok((requires_python, python_pin))
|
||||
} else if let Some(requires_python) = workspace
|
||||
.as_ref()
|
||||
.map(|workspace| find_requires_python(workspace, &DependencyGroupsWithDefaults::none()))
|
||||
.transpose()?
|
||||
.flatten()
|
||||
{
|
||||
// (3) `requires-python` from the workspace
|
||||
let python_request = PythonRequest::Version(VersionRequest::Range(
|
||||
requires_python.specifiers().clone(),
|
||||
PythonVariant::Default,
|
||||
));
|
||||
|
||||
// Pin to the minor version.
|
||||
let python_pin = if pin_python {
|
||||
let interpreter = PythonInstallation::find_or_download(
|
||||
Some(&python_request),
|
||||
EnvironmentPreference::OnlySystem,
|
||||
python_preference,
|
||||
python_downloads,
|
||||
client_builder,
|
||||
cache,
|
||||
Some(reporter),
|
||||
install_mirrors.python_install_mirror.as_deref(),
|
||||
install_mirrors.pypy_install_mirror.as_deref(),
|
||||
install_mirrors.python_downloads_json_url.as_deref(),
|
||||
preview,
|
||||
)
|
||||
.await?
|
||||
.into_interpreter();
|
||||
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinor(
|
||||
interpreter.python_major(),
|
||||
interpreter.python_minor(),
|
||||
PythonVariant::Default,
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
debug!("Using Python version `{requires_python}` from project workspace");
|
||||
|
||||
Ok((requires_python, python_pin))
|
||||
} else {
|
||||
// (4) Default to the system Python
|
||||
let interpreter = PythonInstallation::find_or_download(
|
||||
None,
|
||||
EnvironmentPreference::OnlySystem,
|
||||
python_preference,
|
||||
python_downloads,
|
||||
client_builder,
|
||||
cache,
|
||||
Some(reporter),
|
||||
install_mirrors.python_install_mirror.as_deref(),
|
||||
install_mirrors.pypy_install_mirror.as_deref(),
|
||||
install_mirrors.python_downloads_json_url.as_deref(),
|
||||
preview,
|
||||
)
|
||||
.await?
|
||||
.into_interpreter();
|
||||
|
||||
let requires_python =
|
||||
RequiresPython::greater_than_equal_version(&interpreter.python_minor_version());
|
||||
|
||||
// Pin to the minor version.
|
||||
let python_pin = if pin_python {
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinor(
|
||||
interpreter.python_major(),
|
||||
interpreter.python_minor(),
|
||||
PythonVariant::Default,
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
debug!("Using Python version `{requires_python}` from default interpreter");
|
||||
|
||||
Ok((requires_python, python_pin))
|
||||
}
|
||||
}
|
||||
|
||||
/// The kind of entity to initialize (either a PEP 723 script or a Python project).
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(crate) enum InitKind {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue