From c52b767474320d525de2884f33ca042dcc56d99a Mon Sep 17 00:00:00 2001 From: Jo <10510431+j178@users.noreply.github.com> Date: Tue, 23 Jul 2024 00:09:24 +0800 Subject: [PATCH] `uv init` normalize directory name (#5292) ## Summary Resolves #5255 --- crates/uv/src/commands/project/init.rs | 2 +- crates/uv/tests/init.rs | 51 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/crates/uv/src/commands/project/init.rs b/crates/uv/src/commands/project/init.rs index db3d803b2..76e6e66fe 100644 --- a/crates/uv/src/commands/project/init.rs +++ b/crates/uv/src/commands/project/init.rs @@ -60,7 +60,7 @@ pub(crate) async fn init( } // Create the directory for the project. - let src_dir = path.join("src").join(name.as_ref()); + let src_dir = path.join("src").join(&*name.as_dist_info_name()); fs_err::create_dir_all(&src_dir)?; // Canonicalize the path to the project. diff --git a/crates/uv/tests/init.rs b/crates/uv/tests/init.rs index 626aabb8f..541d68b4a 100644 --- a/crates/uv/tests/init.rs +++ b/crates/uv/tests/init.rs @@ -460,3 +460,54 @@ fn init_workspace_outside() -> Result<()> { Ok(()) } + +#[test] +fn init_invalid_names() -> Result<()> { + let context = TestContext::new("3.12"); + + // `foo-bar` normalized to `foo_bar`. + uv_snapshot!(context.filters(), context.init().current_dir(&context.temp_dir).arg("foo-bar"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + warning: `uv init` is experimental and may change without warning + Initialized project foo-bar in [TEMP_DIR]/foo-bar + "###); + + let child = context.temp_dir.child("foo-bar"); + let pyproject = fs_err::read_to_string(child.join("pyproject.toml"))?; + let _ = fs_err::read_to_string(child.join("src/foo_bar/__init__.py"))?; + + insta::with_settings!({ + filters => context.filters(), + }, { + assert_snapshot!( + pyproject, @r###" + [project] + name = "foo-bar" + version = "0.1.0" + description = "Add your description here" + readme = "README.md" + dependencies = [] + + [tool.uv] + dev-dependencies = [] + "### + ); + }); + + // "bar baz" is not allowed. + uv_snapshot!(context.filters(), context.init().current_dir(&context.temp_dir).arg("bar baz"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + warning: `uv init` is experimental and may change without warning + error: Not a valid package or extra name: "bar baz". Names must start and end with a letter or digit and may only contain -, _, ., and alphanumeric characters. + "###); + + Ok(()) +}