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
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add a `requires-python` field to the `pyproject.toml` and return the corresponding interpreter.
|
let (requires_python, python_pin) = determine_requires_python(
|
||||||
let (requires_python, python_request) = if let Some(python_request) = python_request {
|
path,
|
||||||
// (1) A request from the user or `.python-version` file
|
pin_python,
|
||||||
// This can be arbitrary, i.e., not a version — in which case we may need to resolve the
|
install_mirrors,
|
||||||
// interpreter
|
client_builder,
|
||||||
match python_request {
|
python_preference,
|
||||||
PythonRequest::Version(VersionRequest::MajorMinor(major, minor, variant)) => {
|
python_downloads,
|
||||||
let requires_python = RequiresPython::greater_than_equal_version(&Version::new([
|
cache,
|
||||||
u64::from(major),
|
preview,
|
||||||
u64::from(minor),
|
workspace.as_ref(),
|
||||||
]));
|
&reporter,
|
||||||
|
python_request,
|
||||||
let python_request = if pin_python {
|
)
|
||||||
Some(PythonRequest::Version(VersionRequest::MajorMinor(
|
.await?;
|
||||||
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)
|
|
||||||
};
|
|
||||||
|
|
||||||
project_kind.init(
|
project_kind.init(
|
||||||
name,
|
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
|
// 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())
|
if PythonVersionFile::discover(path, &VersionFileDiscoveryOptions::default())
|
||||||
.await?
|
.await?
|
||||||
.filter(|file| {
|
.filter(|file| {
|
||||||
|
|
@ -645,7 +453,7 @@ async fn init_project(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Write .python-version if it doesn't exist in the project directory.
|
// 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())
|
if PythonVersionFile::discover(path, &VersionFileDiscoveryOptions::default())
|
||||||
.await?
|
.await?
|
||||||
.filter(|file| file.version().is_some())
|
.filter(|file| file.version().is_some())
|
||||||
|
|
@ -663,6 +471,234 @@ async fn init_project(
|
||||||
Ok(())
|
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).
|
/// The kind of entity to initialize (either a PEP 723 script or a Python project).
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub(crate) enum InitKind {
|
pub(crate) enum InitKind {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue