Warn when project-specific settings are passed to non-project `uv run` commands (#5977)

## Summary

Closes https://github.com/astral-sh/uv/issues/5856.
This commit is contained in:
Charlie Marsh 2024-08-09 19:10:33 -04:00 committed by GitHub
parent fcbee9ce25
commit a3b1a4b8da
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 164 additions and 7 deletions

View File

@ -167,10 +167,7 @@ async fn init_project(
printer: Printer,
) -> Result<()> {
// Discover the current workspace, if it exists.
let workspace = if no_workspace {
None
} else {
// Attempt to find a workspace root.
let workspace = {
let parent = path.parent().expect("Project path has no parent");
match Workspace::discover(
parent,
@ -188,6 +185,17 @@ async fn init_project(
}
};
// Ignore the current workspace, if `--no-workspace` was provided.
let workspace = if no_workspace {
// If the user runs with `--no-workspace` and we can't find a workspace, warn.
if workspace.is_none() {
warn_user_once!("`--no-workspace` was provided, but no workspace was found");
}
None
} else {
workspace
};
// Add a `requires-python` field to the `pyproject.toml`.
let requires_python = if let Some(request) = python.as_deref() {
// (1) Explicit request from user

View File

@ -187,11 +187,42 @@ pub(crate) async fn run(
// Discover and sync the base environment.
let temp_dir;
let base_interpreter = if let Some(script_interpreter) = script_interpreter {
// If we found a PEP 723 script and the user provided a project-only setting, warn.
if !extras.is_empty() {
warn_user_once!("Extras are not supported for Python scripts with inline metadata");
}
if !dev {
warn_user_once!("`--no-dev` is not supported for Python scripts with inline metadata");
}
if no_project {
warn_user_once!(
"`--no-project` is a no-op for Python scripts with inline metadata, which always run in isolation"
);
}
if package.is_some() {
warn_user_once!(
"`--package` is a no-op for Python scripts with inline metadata, which always run in isolation"
);
}
if locked {
warn_user_once!(
"`--locked` is a no-op for Python scripts with inline metadata, which always run in isolation"
);
}
if frozen {
warn_user_once!(
"`--frozen` is a no-op for Python scripts with inline metadata, which always run in isolation"
);
}
if isolated {
warn_user_once!(
"`--isolated` is a no-op for Python scripts with inline metadata, which always run in isolation"
);
}
script_interpreter
} else {
let project = if no_project {
None
} else if let Some(package) = package {
let project = if let Some(package) = package {
// We need a workspace, but we don't need to have a current package, we can be e.g. in
// the root of a virtual workspace and then switch into the selected package.
Some(VirtualProject::Project(
@ -209,6 +240,47 @@ pub(crate) async fn run(
}
};
let project = if no_project {
// If the user runs with `--no-project` and we can't find a project, warn.
if project.is_none() {
warn_user_once!("`--no-project` was provided, but no project was found");
}
// If the user ran with `--no-project` and provided a project-only setting, warn.
if !extras.is_empty() {
warn_user_once!("Extras have no effect when used alongside `--no-project`");
}
if !dev {
warn_user_once!("`--no-dev` has no effect when used alongside `--no-project`");
}
if locked {
warn_user_once!("`--locked` has no effect when used alongside `--no-project`");
}
if frozen {
warn_user_once!("`--frozen` has no effect when used alongside `--no-project`");
}
None
} else {
// If we can't find a project and the user provided a project-only setting, warn.
if project.is_none() {
if !extras.is_empty() {
warn_user_once!("Extras have no effect when used outside of a project");
}
if !dev {
warn_user_once!("`--no-dev` has no effect when used outside of a project");
}
if locked {
warn_user_once!("`--locked` has no effect when used outside of a project");
}
if frozen {
warn_user_once!("`--frozen` has no effect when used outside of a project");
}
}
project
};
let interpreter = if let Some(project) = project {
if let Some(project_name) = project.project_name() {
debug!(

View File

@ -704,6 +704,47 @@ fn init_no_workspace() -> Result<()> {
Ok(())
}
/// Warn if the user provides `--no-workspace` outside of a workspace.
#[test]
fn init_no_workspace_warning() -> Result<()> {
let context = TestContext::new("3.12");
uv_snapshot!(context.filters(), context.init().current_dir(&context.temp_dir).arg("--no-workspace").arg("--name").arg("project"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv init` is experimental and may change without warning
warning: `--no-workspace` was provided, but no workspace was found
Initialized project `project`
"###);
let workspace = fs_err::read_to_string(context.temp_dir.join("pyproject.toml"))?;
insta::with_settings!({
filters => context.filters(),
}, {
assert_snapshot!(
workspace, @r###"
[project]
name = "project"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
"###
);
});
Ok(())
}
#[test]
fn init_project_inside_project() -> Result<()> {
let context = TestContext::new("3.12");

View File

@ -320,6 +320,18 @@ fn run_pep723_script() -> Result<()> {
Reading inline script metadata from: main.py
"###);
// Running a script with `--no-project` should warn.
uv_snapshot!(context.filters(), context.run().arg("--preview").arg("--no-project").arg("main.py"), @r###"
success: true
exit_code: 0
----- stdout -----
Hello, world!
----- stderr -----
Reading inline script metadata from: main.py
warning: `--no-project` is a no-op for Python scripts with inline metadata, which always run in isolation
"###);
Ok(())
}
@ -1119,5 +1131,29 @@ fn run_no_project() -> Result<()> {
warning: `uv run` is experimental and may change without warning
"###);
// `run --no-project` should not (but it should still run in the same environment, as it would
// if there were no project at all).
uv_snapshot!(context.filters(), context.run().arg("--no-project").arg("python").arg("-c").arg("import sys; print(sys.executable)"), @r###"
success: true
exit_code: 0
----- stdout -----
[VENV]/[BIN]/python
----- stderr -----
warning: `uv run` is experimental and may change without warning
"###);
// `run --no-project --locked` should fail.
uv_snapshot!(context.filters(), context.run().arg("--no-project").arg("--locked").arg("python").arg("-c").arg("import sys; print(sys.executable)"), @r###"
success: true
exit_code: 0
----- stdout -----
[VENV]/[BIN]/python
----- stderr -----
warning: `uv run` is experimental and may change without warning
warning: `--locked` has no effect when used alongside `--no-project`
"###);
Ok(())
}