mirror of https://github.com/astral-sh/uv
Pin `.python-version` in `uv init` (#6869)
## Summary I'm not convinced that the behavior is correct as-implemented. When the user passes a `--python >=3.8` or we discover a `requires-python` from the workspace, we're currently writing that request out to `.python-version`. I would probably rather that we write the resolved patch version? Closes https://github.com/astral-sh/uv/issues/6821.
This commit is contained in:
parent
3e8d53c8eb
commit
50d7b9c38a
|
|
@ -2184,6 +2184,14 @@ pub struct InitArgs {
|
|||
#[arg(long)]
|
||||
pub no_readme: bool,
|
||||
|
||||
/// Do not create a `.python-version` file for the project.
|
||||
///
|
||||
/// By default, uv will create a `.python-version` file containing the minor version of
|
||||
/// the discovered Python interpreter, which will cause subsequent uv commands to use that
|
||||
/// version.
|
||||
#[arg(long)]
|
||||
pub no_pin_python: bool,
|
||||
|
||||
/// Avoid discovering a workspace and create a standalone project.
|
||||
///
|
||||
/// By default, uv searches for workspaces in the current directory or any
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ impl PythonVersionFile {
|
|||
|
||||
/// Create a new representation of a version file at the given path.
|
||||
///
|
||||
/// The file will not any versions; see [`PythonVersionFile::with_versions`].
|
||||
/// The file will not any include versions; see [`PythonVersionFile::with_versions`].
|
||||
/// The file will not be created; see [`PythonVersionFile::write`].
|
||||
pub fn new(path: PathBuf) -> Self {
|
||||
Self {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use uv_client::{BaseClientBuilder, Connectivity};
|
|||
use uv_fs::{Simplified, CWD};
|
||||
use uv_python::{
|
||||
EnvironmentPreference, PythonDownloads, PythonInstallation, PythonPreference, PythonRequest,
|
||||
VersionRequest,
|
||||
PythonVersionFile, VersionRequest,
|
||||
};
|
||||
use uv_resolver::RequiresPython;
|
||||
use uv_workspace::pyproject_mut::{DependencyTarget, PyProjectTomlMut};
|
||||
|
|
@ -30,6 +30,7 @@ pub(crate) async fn init(
|
|||
package: bool,
|
||||
project_kind: InitProjectKind,
|
||||
no_readme: bool,
|
||||
no_pin_python: bool,
|
||||
python: Option<String>,
|
||||
no_workspace: bool,
|
||||
python_preference: PythonPreference,
|
||||
|
|
@ -73,6 +74,7 @@ pub(crate) async fn init(
|
|||
package,
|
||||
project_kind,
|
||||
no_readme,
|
||||
no_pin_python,
|
||||
python,
|
||||
no_workspace,
|
||||
python_preference,
|
||||
|
|
@ -121,6 +123,7 @@ async fn init_project(
|
|||
package: bool,
|
||||
project_kind: InitProjectKind,
|
||||
no_readme: bool,
|
||||
no_pin_python: bool,
|
||||
python: Option<String>,
|
||||
no_workspace: bool,
|
||||
python_preference: PythonPreference,
|
||||
|
|
@ -173,33 +176,77 @@ async fn init_project(
|
|||
}
|
||||
};
|
||||
|
||||
// Add a `requires-python` field to the `pyproject.toml`.
|
||||
let requires_python = if let Some(request) = python.as_deref() {
|
||||
let reporter = PythonDownloadReporter::single(printer);
|
||||
let client_builder = BaseClientBuilder::new()
|
||||
.connectivity(connectivity)
|
||||
.native_tls(native_tls);
|
||||
|
||||
// Add a `requires-python` field to the `pyproject.toml` and return the corresponding interpreter.
|
||||
let (requires_python, python_request) = if let Some(request) = python.as_deref() {
|
||||
// (1) Explicit request from user
|
||||
match PythonRequest::parse(request) {
|
||||
PythonRequest::Version(VersionRequest::MajorMinor(major, minor)) => {
|
||||
RequiresPython::greater_than_equal_version(&Version::new([
|
||||
let requires_python = RequiresPython::greater_than_equal_version(&Version::new([
|
||||
u64::from(major),
|
||||
u64::from(minor),
|
||||
]))
|
||||
]));
|
||||
|
||||
let python_request = if no_pin_python {
|
||||
None
|
||||
} else {
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinor(
|
||||
major, minor,
|
||||
)))
|
||||
};
|
||||
|
||||
(requires_python, python_request)
|
||||
}
|
||||
PythonRequest::Version(VersionRequest::MajorMinorPatch(major, minor, patch)) => {
|
||||
RequiresPython::greater_than_equal_version(&Version::new([
|
||||
let requires_python = RequiresPython::greater_than_equal_version(&Version::new([
|
||||
u64::from(major),
|
||||
u64::from(minor),
|
||||
u64::from(patch),
|
||||
]))
|
||||
]));
|
||||
|
||||
let python_request = if no_pin_python {
|
||||
None
|
||||
} else {
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinorPatch(
|
||||
major, minor, patch,
|
||||
)))
|
||||
};
|
||||
|
||||
(requires_python, python_request)
|
||||
}
|
||||
PythonRequest::Version(VersionRequest::Range(specifiers)) => {
|
||||
RequiresPython::from_specifiers(&specifiers)?
|
||||
ref python_request @ PythonRequest::Version(VersionRequest::Range(ref specifiers)) => {
|
||||
let requires_python = RequiresPython::from_specifiers(specifiers)?;
|
||||
|
||||
let python_request = if no_pin_python {
|
||||
None
|
||||
} else {
|
||||
let interpreter = PythonInstallation::find_or_download(
|
||||
Some(python_request),
|
||||
EnvironmentPreference::Any,
|
||||
python_preference,
|
||||
python_downloads,
|
||||
&client_builder,
|
||||
cache,
|
||||
Some(&reporter),
|
||||
)
|
||||
.await?
|
||||
.into_interpreter();
|
||||
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinor(
|
||||
interpreter.python_major(),
|
||||
interpreter.python_minor(),
|
||||
)))
|
||||
};
|
||||
|
||||
(requires_python, python_request)
|
||||
}
|
||||
request => {
|
||||
let reporter = PythonDownloadReporter::single(printer);
|
||||
let client_builder = BaseClientBuilder::new()
|
||||
.connectivity(connectivity)
|
||||
.native_tls(native_tls);
|
||||
python_request => {
|
||||
let interpreter = PythonInstallation::find_or_download(
|
||||
Some(&request),
|
||||
Some(&python_request),
|
||||
EnvironmentPreference::Any,
|
||||
python_preference,
|
||||
python_downloads,
|
||||
|
|
@ -209,7 +256,20 @@ async fn init_project(
|
|||
)
|
||||
.await?
|
||||
.into_interpreter();
|
||||
RequiresPython::greater_than_equal_version(&interpreter.python_minor_version())
|
||||
|
||||
let requires_python =
|
||||
RequiresPython::greater_than_equal_version(&interpreter.python_minor_version());
|
||||
|
||||
let python_request = if no_pin_python {
|
||||
None
|
||||
} else {
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinor(
|
||||
interpreter.python_major(),
|
||||
interpreter.python_minor(),
|
||||
)))
|
||||
};
|
||||
|
||||
(requires_python, python_request)
|
||||
}
|
||||
}
|
||||
} else if let Some(requires_python) = workspace
|
||||
|
|
@ -217,16 +277,36 @@ async fn init_project(
|
|||
.and_then(|workspace| find_requires_python(workspace).ok().flatten())
|
||||
{
|
||||
// (2) `Requires-Python` from the workspace
|
||||
requires_python
|
||||
let python_request =
|
||||
PythonRequest::Version(VersionRequest::Range(requires_python.specifiers().clone()));
|
||||
|
||||
// Pin to the minor version.
|
||||
let python_request = if no_pin_python {
|
||||
None
|
||||
} else {
|
||||
let interpreter = PythonInstallation::find_or_download(
|
||||
Some(&python_request),
|
||||
EnvironmentPreference::Any,
|
||||
python_preference,
|
||||
python_downloads,
|
||||
&client_builder,
|
||||
cache,
|
||||
Some(&reporter),
|
||||
)
|
||||
.await?
|
||||
.into_interpreter();
|
||||
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinor(
|
||||
interpreter.python_major(),
|
||||
interpreter.python_minor(),
|
||||
)))
|
||||
};
|
||||
|
||||
(requires_python, python_request)
|
||||
} else {
|
||||
// (3) Default to the system Python
|
||||
let request = PythonRequest::Any;
|
||||
let reporter = PythonDownloadReporter::single(printer);
|
||||
let client_builder = BaseClientBuilder::new()
|
||||
.connectivity(connectivity)
|
||||
.native_tls(native_tls);
|
||||
let interpreter = PythonInstallation::find_or_download(
|
||||
Some(&request),
|
||||
None,
|
||||
EnvironmentPreference::Any,
|
||||
python_preference,
|
||||
python_downloads,
|
||||
|
|
@ -236,10 +316,33 @@ async fn init_project(
|
|||
)
|
||||
.await?
|
||||
.into_interpreter();
|
||||
RequiresPython::greater_than_equal_version(&interpreter.python_minor_version())
|
||||
|
||||
let requires_python =
|
||||
RequiresPython::greater_than_equal_version(&interpreter.python_minor_version());
|
||||
|
||||
// Pin to the minor version.
|
||||
let python_request = if no_pin_python {
|
||||
None
|
||||
} else {
|
||||
Some(PythonRequest::Version(VersionRequest::MajorMinor(
|
||||
interpreter.python_major(),
|
||||
interpreter.python_minor(),
|
||||
)))
|
||||
};
|
||||
|
||||
(requires_python, python_request)
|
||||
};
|
||||
|
||||
project_kind.init(name, path, &requires_python, no_readme, package)?;
|
||||
project_kind
|
||||
.init(
|
||||
name,
|
||||
path,
|
||||
&requires_python,
|
||||
python_request.as_ref(),
|
||||
no_readme,
|
||||
package,
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(workspace) = workspace {
|
||||
if workspace.excludes(path)? {
|
||||
|
|
@ -284,7 +387,7 @@ async fn init_project(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
pub(crate) enum InitProjectKind {
|
||||
#[default]
|
||||
Application,
|
||||
|
|
@ -293,55 +396,145 @@ pub(crate) enum InitProjectKind {
|
|||
|
||||
impl InitProjectKind {
|
||||
/// Initialize this project kind at the target path.
|
||||
fn init(
|
||||
&self,
|
||||
async fn init(
|
||||
self,
|
||||
name: &PackageName,
|
||||
path: &Path,
|
||||
requires_python: &RequiresPython,
|
||||
python_request: Option<&PythonRequest>,
|
||||
no_readme: bool,
|
||||
package: bool,
|
||||
) -> Result<()> {
|
||||
match self {
|
||||
InitProjectKind::Application => {
|
||||
init_application(name, path, requires_python, no_readme, package)
|
||||
self.init_application(
|
||||
name,
|
||||
path,
|
||||
requires_python,
|
||||
python_request,
|
||||
no_readme,
|
||||
package,
|
||||
)
|
||||
.await
|
||||
}
|
||||
InitProjectKind::Library => {
|
||||
init_library(name, path, requires_python, no_readme, package)
|
||||
self.init_library(
|
||||
name,
|
||||
path,
|
||||
requires_python,
|
||||
python_request,
|
||||
no_readme,
|
||||
package,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether or not this project kind is packaged by default.
|
||||
pub(crate) fn packaged_by_default(&self) -> bool {
|
||||
/// Whether this project kind is packaged by default.
|
||||
pub(crate) fn packaged_by_default(self) -> bool {
|
||||
matches!(self, InitProjectKind::Library)
|
||||
}
|
||||
}
|
||||
|
||||
fn init_application(
|
||||
name: &PackageName,
|
||||
path: &Path,
|
||||
requires_python: &RequiresPython,
|
||||
no_readme: bool,
|
||||
package: bool,
|
||||
) -> Result<()> {
|
||||
// Create the `pyproject.toml`
|
||||
let mut pyproject = pyproject_project(name, requires_python, no_readme);
|
||||
async fn init_application(
|
||||
self,
|
||||
name: &PackageName,
|
||||
path: &Path,
|
||||
requires_python: &RequiresPython,
|
||||
python_request: Option<&PythonRequest>,
|
||||
no_readme: bool,
|
||||
package: bool,
|
||||
) -> Result<()> {
|
||||
// Create the `pyproject.toml`
|
||||
let mut pyproject = pyproject_project(name, requires_python, no_readme);
|
||||
|
||||
// Include additional project configuration for packaged applications
|
||||
if package {
|
||||
// Since it'll be packaged, we can add a `[project.scripts]` entry
|
||||
pyproject.push('\n');
|
||||
pyproject.push_str(&pyproject_project_scripts(name, "hello", "hello"));
|
||||
// Include additional project configuration for packaged applications
|
||||
if package {
|
||||
// Since it'll be packaged, we can add a `[project.scripts]` entry
|
||||
pyproject.push('\n');
|
||||
pyproject.push_str(&pyproject_project_scripts(name, "hello", "hello"));
|
||||
|
||||
// Add a build system
|
||||
pyproject.push('\n');
|
||||
pyproject.push_str(pyproject_build_system());
|
||||
// Add a build system
|
||||
pyproject.push('\n');
|
||||
pyproject.push_str(pyproject_build_system());
|
||||
}
|
||||
|
||||
fs_err::create_dir_all(path)?;
|
||||
|
||||
// Create the source structure.
|
||||
if package {
|
||||
// Create `src/{name}/__init__.py`, if it doesn't exist already.
|
||||
let src_dir = path.join("src").join(&*name.as_dist_info_name());
|
||||
let init_py = src_dir.join("__init__.py");
|
||||
if !init_py.try_exists()? {
|
||||
fs_err::create_dir_all(&src_dir)?;
|
||||
fs_err::write(
|
||||
init_py,
|
||||
indoc::formatdoc! {r#"
|
||||
def hello():
|
||||
print("Hello from {name}!")
|
||||
"#},
|
||||
)?;
|
||||
}
|
||||
} else {
|
||||
// Create `hello.py` if it doesn't exist
|
||||
// TODO(zanieb): Only create `hello.py` if there are no other Python files?
|
||||
let hello_py = path.join("hello.py");
|
||||
if !hello_py.try_exists()? {
|
||||
fs_err::write(
|
||||
path.join("hello.py"),
|
||||
indoc::formatdoc! {r#"
|
||||
def main():
|
||||
print("Hello from {name}!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
"#},
|
||||
)?;
|
||||
}
|
||||
}
|
||||
fs_err::write(path.join("pyproject.toml"), pyproject)?;
|
||||
|
||||
// Write .python-version if it doesn't exist.
|
||||
if let Some(python_request) = python_request {
|
||||
if PythonVersionFile::discover(path, false, false)
|
||||
.await?
|
||||
.is_none()
|
||||
{
|
||||
PythonVersionFile::new(path.join(".python-version"))
|
||||
.with_versions(vec![python_request.clone()])
|
||||
.write()
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fs_err::create_dir_all(path)?;
|
||||
async fn init_library(
|
||||
self,
|
||||
name: &PackageName,
|
||||
path: &Path,
|
||||
requires_python: &RequiresPython,
|
||||
python_request: Option<&PythonRequest>,
|
||||
no_readme: bool,
|
||||
package: bool,
|
||||
) -> Result<()> {
|
||||
if !package {
|
||||
return Err(anyhow!("Library projects must be packaged"));
|
||||
}
|
||||
|
||||
// Create the `pyproject.toml`
|
||||
let mut pyproject = pyproject_project(name, requires_python, no_readme);
|
||||
|
||||
// Always include a build system if the project is packaged.
|
||||
pyproject.push('\n');
|
||||
pyproject.push_str(pyproject_build_system());
|
||||
|
||||
fs_err::create_dir_all(path)?;
|
||||
fs_err::write(path.join("pyproject.toml"), pyproject)?;
|
||||
|
||||
// Create the source structure.
|
||||
if package {
|
||||
// Create `src/{name}/__init__.py`, if it doesn't exist already.
|
||||
let src_dir = path.join("src").join(&*name.as_dist_info_name());
|
||||
let init_py = src_dir.join("__init__.py");
|
||||
|
|
@ -350,70 +543,27 @@ fn init_application(
|
|||
fs_err::write(
|
||||
init_py,
|
||||
indoc::formatdoc! {r#"
|
||||
def hello():
|
||||
print("Hello from {name}!")
|
||||
def hello() -> str:
|
||||
return "Hello from {name}!"
|
||||
"#},
|
||||
)?;
|
||||
}
|
||||
} else {
|
||||
// Create `hello.py` if it doesn't exist
|
||||
// TODO(zanieb): Only create `hello.py` if there are no other Python files?
|
||||
let hello_py = path.join("hello.py");
|
||||
if !hello_py.try_exists()? {
|
||||
fs_err::write(
|
||||
path.join("hello.py"),
|
||||
indoc::formatdoc! {r#"
|
||||
def main():
|
||||
print("Hello from {name}!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
"#},
|
||||
)?;
|
||||
// Write .python-version if it doesn't exist.
|
||||
if let Some(python_request) = python_request {
|
||||
if PythonVersionFile::discover(path, false, false)
|
||||
.await?
|
||||
.is_none()
|
||||
{
|
||||
PythonVersionFile::new(path.join(".python-version"))
|
||||
.with_versions(vec![python_request.clone()])
|
||||
.write()
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fs_err::write(path.join("pyproject.toml"), pyproject)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init_library(
|
||||
name: &PackageName,
|
||||
path: &Path,
|
||||
requires_python: &RequiresPython,
|
||||
no_readme: bool,
|
||||
package: bool,
|
||||
) -> Result<()> {
|
||||
if !package {
|
||||
return Err(anyhow!("Library projects must be packaged"));
|
||||
}
|
||||
|
||||
// Create the `pyproject.toml`
|
||||
let mut pyproject = pyproject_project(name, requires_python, no_readme);
|
||||
|
||||
// Always include a build system if the project is packaged.
|
||||
pyproject.push('\n');
|
||||
pyproject.push_str(pyproject_build_system());
|
||||
|
||||
fs_err::create_dir_all(path)?;
|
||||
fs_err::write(path.join("pyproject.toml"), pyproject)?;
|
||||
|
||||
// Create `src/{name}/__init__.py`, if it doesn't exist already.
|
||||
let src_dir = path.join("src").join(&*name.as_dist_info_name());
|
||||
let init_py = src_dir.join("__init__.py");
|
||||
if !init_py.try_exists()? {
|
||||
fs_err::create_dir_all(&src_dir)?;
|
||||
fs_err::write(
|
||||
init_py,
|
||||
indoc::formatdoc! {r#"
|
||||
def hello() -> str:
|
||||
return "Hello from {name}!"
|
||||
"#},
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Generate the `[project]` section of a `pyproject.toml`.
|
||||
|
|
|
|||
|
|
@ -1028,6 +1028,7 @@ async fn run_project(
|
|||
args.package,
|
||||
args.kind,
|
||||
args.no_readme,
|
||||
args.no_pin_python,
|
||||
args.python,
|
||||
args.no_workspace,
|
||||
globals.python_preference,
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@ pub(crate) struct InitSettings {
|
|||
pub(crate) package: bool,
|
||||
pub(crate) kind: InitProjectKind,
|
||||
pub(crate) no_readme: bool,
|
||||
pub(crate) no_pin_python: bool,
|
||||
pub(crate) no_workspace: bool,
|
||||
pub(crate) python: Option<String>,
|
||||
}
|
||||
|
|
@ -174,6 +175,7 @@ impl InitSettings {
|
|||
app,
|
||||
lib,
|
||||
no_readme,
|
||||
no_pin_python,
|
||||
no_workspace,
|
||||
python,
|
||||
} = args;
|
||||
|
|
@ -193,6 +195,7 @@ impl InitSettings {
|
|||
package,
|
||||
kind,
|
||||
no_readme,
|
||||
no_pin_python,
|
||||
no_workspace,
|
||||
python,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,16 @@ fn init() -> Result<()> {
|
|||
Resolved 1 package in [TIME]
|
||||
"###);
|
||||
|
||||
let python_version =
|
||||
fs_err::read_to_string(context.temp_dir.join("foo").join(".python-version"))?;
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
assert_snapshot!(
|
||||
python_version, @"3.12"
|
||||
);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -455,6 +465,40 @@ fn init_no_readme() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn init_no_pin_python() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
uv_snapshot!(context.filters(), context.init().arg("foo").arg("--no-pin-python"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Initialized project `foo` at `[TEMP_DIR]/foo`
|
||||
"###);
|
||||
|
||||
let pyproject = fs_err::read_to_string(context.temp_dir.join("foo/pyproject.toml"))?;
|
||||
let _ = fs_err::read_to_string(context.temp_dir.join("foo/.python-version")).unwrap_err();
|
||||
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
assert_snapshot!(
|
||||
pyproject, @r###"
|
||||
[project]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = []
|
||||
"###
|
||||
);
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn init_library_current_dir() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
|
@ -1618,6 +1662,15 @@ fn init_requires_python_workspace() -> Result<()> {
|
|||
);
|
||||
});
|
||||
|
||||
let python_version = fs_err::read_to_string(child.join(".python-version"))?;
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
assert_snapshot!(
|
||||
python_version, @"3.12"
|
||||
);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -1667,6 +1720,15 @@ fn init_requires_python_version() -> Result<()> {
|
|||
);
|
||||
});
|
||||
|
||||
let python_version = fs_err::read_to_string(child.join(".python-version"))?;
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
assert_snapshot!(
|
||||
python_version, @"3.8"
|
||||
);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -1674,7 +1736,7 @@ fn init_requires_python_version() -> Result<()> {
|
|||
/// specifiers verbatim.
|
||||
#[test]
|
||||
fn init_requires_python_specifiers() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
let context = TestContext::new_with_versions(&["3.8", "3.12"]);
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(indoc! {
|
||||
|
|
@ -1717,6 +1779,15 @@ fn init_requires_python_specifiers() -> Result<()> {
|
|||
);
|
||||
});
|
||||
|
||||
let python_version = fs_err::read_to_string(child.join(".python-version"))?;
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
assert_snapshot!(
|
||||
python_version, @"3.8"
|
||||
);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -453,6 +453,10 @@ uv init [OPTIONS] [PATH]
|
|||
|
||||
<p>This is the default behavior when using <code>--app</code>.</p>
|
||||
|
||||
</dd><dt><code>--no-pin-python</code></dt><dd><p>Do not create a <code>.python-version</code> file for the project.</p>
|
||||
|
||||
<p>By default, uv will create a <code>.python-version</code> file containing the minor version of the discovered Python interpreter, which will cause subsequent uv commands to use that version.</p>
|
||||
|
||||
</dd><dt><code>--no-progress</code></dt><dd><p>Hide all progress outputs.</p>
|
||||
|
||||
<p>For example, spinners or progress bars.</p>
|
||||
|
|
|
|||
Loading…
Reference in New Issue