From 77fecc5c27c8785ec1ea9c545d6c140ce5fa78f1 Mon Sep 17 00:00:00 2001 From: liam Date: Sun, 2 Nov 2025 19:26:09 -0500 Subject: [PATCH] Improve `uv init` error for invalid directory names (#16554) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves https://github.com/astral-sh/uv/issues/16433 When `uv init` infers a project name from the working directory, directories with characters outside the PEP 503 rules produced the generic “Not a valid package or extra name” message that didn’t explain the source of the problem. This change intercepts that failure, reports whether the current or explicit target directory caused it, and tells the user to supply an explicit `--name`. --- crates/uv/src/commands/project/init.rs | 18 +++++++++++++++--- crates/uv/tests/it/init.rs | 24 +++++++++++++++++++++++- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/crates/uv/src/commands/project/init.rs b/crates/uv/src/commands/project/init.rs index 9b0641b66..b540238e2 100644 --- a/crates/uv/src/commands/project/init.rs +++ b/crates/uv/src/commands/project/init.rs @@ -116,15 +116,27 @@ pub(crate) async fn init( let name = match name { Some(name) => name, None => { - let name = path + let directory_name = path .file_name() .and_then(|path| path.to_str()) .context("Missing directory name")?; // Pre-normalize the package name by removing any leading or trailing // whitespace, and replacing any internal whitespace with hyphens. - let name = name.trim().replace(' ', "-"); - PackageName::from_owned(name)? + let candidate = directory_name.trim().replace(' ', "-"); + match PackageName::from_owned(candidate) { + Ok(name) => name, + Err(_) => { + let directory_description = if explicit_path.is_some() { + "target directory" + } else { + "current directory" + }; + anyhow::bail!( + "The {directory_description} (`{directory_name}`) is not a valid package name. Please provide a package name with `--name`." + ); + } + } } }; diff --git a/crates/uv/tests/it/init.rs b/crates/uv/tests/it/init.rs index 96a5557bc..921b27c4e 100644 --- a/crates/uv/tests/it/init.rs +++ b/crates/uv/tests/it/init.rs @@ -2659,10 +2659,32 @@ fn init_hidden() { ----- stdout ----- ----- stderr ----- - error: Not a valid package or extra name: ".foo". Names must start and end with a letter or digit and may only contain -, _, ., and alphanumeric characters. + error: The target directory (`.foo`) is not a valid package name. Please provide a package name with `--name`. "###); } +#[test] +fn init_non_ascii_directory() -> Result<()> { + let context = TestContext::new("3.12"); + + let directory = context.temp_dir.child("püthon"); + directory.create_dir_all()?; + + let mut command = context.init(); + command.current_dir(directory.path()); + + uv_snapshot!(context.filters(), command, @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: The current directory (`püthon`) is not a valid package name. Please provide a package name with `--name`. + "###); + + Ok(()) +} + /// Run `uv init` with an invalid `pyproject.toml` in a parent directory. #[test] fn init_failure() -> Result<()> {