support `--no-project` in `uv format` (#15572)

When a user passes `--no-project` argument to `uv format` command,
instead of running the formatter in the context of the current project,
run it in the context of the current directory. This is useful when the
current directory is not a project.

Closes https://github.com/astral-sh/uv/issues/15462
This commit is contained in:
Yiğit Ö. Ünver 2025-09-09 00:16:40 +03:00 committed by GitHub
parent bd36952492
commit 19ea0f4932
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 51 additions and 3 deletions

View File

@ -4461,6 +4461,14 @@ pub struct FormatArgs {
/// `uv format -- src/module/foo.py` to format a specific file.
#[arg(last = true)]
pub extra_args: Vec<String>,
/// Avoid discovering a project or workspace.
///
/// Instead of running the formatter in the context of the current project, run it in the
/// context of the current directory. This is useful when the current directory is not a
/// project.
#[arg(long)]
pub no_project: bool,
}
#[derive(Args)]

View File

@ -29,6 +29,7 @@ pub(crate) async fn format(
cache: Cache,
printer: Printer,
preview: Preview,
no_project: bool,
) -> Result<ExitStatus> {
// Check if the format feature is in preview
if !preview.is_enabled(PreviewFeatures::FORMAT) {
@ -39,7 +40,11 @@ pub(crate) async fn format(
}
let workspace_cache = WorkspaceCache::default();
let target_dir =
// If `no_project` is provided, we use the provided directory
// Otherwise, we discover the project and use the project root.
let target_dir = if no_project {
project_dir.to_owned()
} else {
match VirtualProject::discover(project_dir, &DiscoveryOptions::default(), &workspace_cache)
.await
{
@ -53,7 +58,8 @@ pub(crate) async fn format(
| WorkspaceError::NonWorkspace(_),
) => project_dir.to_owned(),
Err(err) => return Err(err.into()),
};
}
};
// Parse version if provided
let version = version.as_deref().map(Version::from_str).transpose()?;

View File

@ -2283,6 +2283,7 @@ async fn run_project(
cache,
printer,
globals.preview,
args.no_project,
))
.await
}

View File

@ -1911,6 +1911,7 @@ pub(crate) struct FormatSettings {
pub(crate) diff: bool,
pub(crate) extra_args: Vec<String>,
pub(crate) version: Option<String>,
pub(crate) no_project: bool,
}
impl FormatSettings {
@ -1921,6 +1922,7 @@ impl FormatSettings {
diff,
extra_args,
version,
no_project,
} = args;
Self {
@ -1928,6 +1930,7 @@ impl FormatSettings {
diff,
extra_args,
version,
no_project,
}
}
}

View File

@ -187,6 +187,34 @@ fn format_from_project_root() -> Result<()> {
Ok(())
}
#[test]
fn format_no_project() -> Result<()> {
let context = TestContext::new_with_versions(&[]);
let main_py = context.temp_dir.child("main.py");
main_py.write_str(indoc! {r"
x = 1
"})?;
uv_snapshot!(context.filters(), context.format().arg("--no-project"), @r"
success: true
exit_code: 0
----- stdout -----
1 file reformatted
----- stderr -----
warning: `uv format` is experimental and may change without warning. Pass `--preview-features format` to disable this warning.
");
// Check that the file was formatted
let formatted_content = fs_err::read_to_string(&main_py)?;
assert_snapshot!(formatted_content, @r"
x = 1
");
Ok(())
}
#[test]
fn format_relative_project() -> Result<()> {
let context = TestContext::new_with_versions(&[]);

View File

@ -2279,7 +2279,9 @@ uv format [OPTIONS] [-- <EXTRA_ARGS>...]
<p>Instead, uv will search for a suitable Python version on the system.</p>
<p>May also be set with the <code>UV_NO_MANAGED_PYTHON</code> environment variable.</p></dd><dt id="uv-format--no-progress"><a href="#uv-format--no-progress"><code>--no-progress</code></a></dt><dd><p>Hide all progress outputs.</p>
<p>For example, spinners or progress bars.</p>
<p>May also be set with the <code>UV_NO_PROGRESS</code> environment variable.</p></dd><dt id="uv-format--no-python-downloads"><a href="#uv-format--no-python-downloads"><code>--no-python-downloads</code></a></dt><dd><p>Disable automatic downloads of Python.</p>
<p>May also be set with the <code>UV_NO_PROGRESS</code> environment variable.</p></dd><dt id="uv-format--no-project"><a href="#uv-format--no-project"><code>--no-project</code></a></dt><dd><p>Avoid discovering a project or workspace.</p>
<p>Instead of running the formatter in the context of the current project, run it in the context of the current directory. This is useful when the current directory is not a project.</p>
</dd><dt id="uv-format--no-python-downloads"><a href="#uv-format--no-python-downloads"><code>--no-python-downloads</code></a></dt><dd><p>Disable automatic downloads of Python.</p>
</dd><dt id="uv-format--offline"><a href="#uv-format--offline"><code>--offline</code></a></dt><dd><p>Disable network access.</p>
<p>When disabled, uv will only use locally cached data and locally available files.</p>
<p>May also be set with the <code>UV_OFFLINE</code> environment variable.</p></dd><dt id="uv-format--project"><a href="#uv-format--project"><code>--project</code></a> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>