Skip to content

Commit 3c9aea8

Browse files
konstinzanieb
authored andcommitted
uv init: Make uv_build the default build backend (from hatchling) (#14661)
Closes #14298 Switch the default build backend for `uv init` from `hatchling` to `uv_build`. This change affects the following two commands: * `uv init --lib` * `uv init [--app] --package` It does not affect `uv init` or `uv init --app` without `--package`. `uv init --build-backend <...>` also works as before. **Before** ``` $ uv init --lib project $ cat project/pyproject.toml [project] name = "project" version = "0.1.0" description = "Add your description here" readme = "README.md" authors = [ { name = "konstin", email = "konstin@mailbox.org" } ] requires-python = ">=3.13.2" dependencies = [] [build-system] requires = ["hatchling"] build-backend = "hatchling.build" ``` **After** ``` $ uv init --lib project $ cat project/pyproject.toml [project] name = "project" version = "0.1.0" description = "Add your description here" readme = "README.md" authors = [ { name = "konstin", email = "konstin@mailbox.org" } ] requires-python = ">=3.13.2" dependencies = [] [build-system] requires = ["uv_build>=0.7.20,<0.8"] build-backend = "uv_build" ``` I cleaned up some tests for consistency in the second commit.
1 parent 95c0b71 commit 3c9aea8

7 files changed

Lines changed: 99 additions & 223 deletions

File tree

crates/uv-build-backend/src/metadata.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ impl PyProjectToml {
171171
///
172172
/// ```toml
173173
/// [build-system]
174-
/// requires = ["uv_build>=0.4.15,<5"]
174+
/// requires = ["uv_build>=0.4.15,<0.5"]
175175
/// build-backend = "uv_build"
176176
/// ```
177177
pub fn check_build_system(&self, uv_version: &str) -> Vec<String> {
@@ -826,7 +826,7 @@ mod tests {
826826
{payload}
827827
828828
[build-system]
829-
requires = ["uv_build>=0.4.15,<5"]
829+
requires = ["uv_build>=0.4.15,<0.5"]
830830
build-backend = "uv_build"
831831
"#
832832
}
@@ -909,7 +909,7 @@ mod tests {
909909
foo-bar = "foo:bar"
910910
911911
[build-system]
912-
requires = ["uv_build>=0.4.15,<5"]
912+
requires = ["uv_build>=0.4.15,<0.5"]
913913
build-backend = "uv_build"
914914
"#
915915
};
@@ -1036,7 +1036,7 @@ mod tests {
10361036
foo-bar = "foo:bar"
10371037
10381038
[build-system]
1039-
requires = ["uv_build>=0.4.15,<5"]
1039+
requires = ["uv_build>=0.4.15,<0.5"]
10401040
build-backend = "uv_build"
10411041
"#
10421042
};
@@ -1104,7 +1104,7 @@ mod tests {
11041104
let contents = extend_project("");
11051105
let pyproject_toml = PyProjectToml::parse(&contents).unwrap();
11061106
assert_snapshot!(
1107-
pyproject_toml.check_build_system("1.0.0+test").join("\n"),
1107+
pyproject_toml.check_build_system("0.4.15+test").join("\n"),
11081108
@""
11091109
);
11101110
}
@@ -1135,7 +1135,7 @@ mod tests {
11351135
version = "0.1.0"
11361136
11371137
[build-system]
1138-
requires = ["uv_build>=0.4.15,<5", "wheel"]
1138+
requires = ["uv_build>=0.4.15,<0.5", "wheel"]
11391139
build-backend = "uv_build"
11401140
"#};
11411141
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
@@ -1171,7 +1171,7 @@ mod tests {
11711171
version = "0.1.0"
11721172
11731173
[build-system]
1174-
requires = ["uv_build>=0.4.15,<5"]
1174+
requires = ["uv_build>=0.4.15,<0.5"]
11751175
build-backend = "setuptools"
11761176
"#};
11771177
let pyproject_toml = PyProjectToml::parse(contents).unwrap();

crates/uv/src/commands/project/init.rs

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,6 @@ pub(crate) async fn init(
6363
printer: Printer,
6464
preview: PreviewMode,
6565
) -> Result<ExitStatus> {
66-
if build_backend == Some(ProjectBuildBackend::Uv) && preview.is_disabled() {
67-
warn_user_once!("The uv build backend is experimental and may change without warning");
68-
}
6966
match init_kind {
7067
InitKind::Script => {
7168
let Some(path) = explicit_path.as_deref() else {
@@ -596,7 +593,6 @@ async fn init_project(
596593
author_from,
597594
no_readme,
598595
package,
599-
preview,
600596
)?;
601597

602598
if let Some(workspace) = workspace {
@@ -724,7 +720,6 @@ impl InitProjectKind {
724720
author_from: Option<AuthorFrom>,
725721
no_readme: bool,
726722
package: bool,
727-
preview: PreviewMode,
728723
) -> Result<()> {
729724
match self {
730725
InitProjectKind::Application => InitProjectKind::init_application(
@@ -739,7 +734,6 @@ impl InitProjectKind {
739734
author_from,
740735
no_readme,
741736
package,
742-
preview,
743737
),
744738
InitProjectKind::Library => InitProjectKind::init_library(
745739
name,
@@ -753,7 +747,6 @@ impl InitProjectKind {
753747
author_from,
754748
no_readme,
755749
package,
756-
preview,
757750
),
758751
}
759752
}
@@ -772,7 +765,6 @@ impl InitProjectKind {
772765
author_from: Option<AuthorFrom>,
773766
no_readme: bool,
774767
package: bool,
775-
preview: PreviewMode,
776768
) -> Result<()> {
777769
fs_err::create_dir_all(path)?;
778770

@@ -805,11 +797,7 @@ impl InitProjectKind {
805797
}
806798

807799
// Add a build system
808-
let build_backend = match build_backend {
809-
Some(build_backend) => build_backend,
810-
None if preview.is_enabled() => ProjectBuildBackend::Uv,
811-
None => ProjectBuildBackend::Hatch,
812-
};
800+
let build_backend = build_backend.unwrap_or(ProjectBuildBackend::Uv);
813801
pyproject.push('\n');
814802
pyproject.push_str(&pyproject_build_system(name, build_backend));
815803
pyproject_build_backend_prerequisites(name, path, build_backend)?;
@@ -859,7 +847,6 @@ impl InitProjectKind {
859847
author_from: Option<AuthorFrom>,
860848
no_readme: bool,
861849
package: bool,
862-
preview: PreviewMode,
863850
) -> Result<()> {
864851
if !package {
865852
return Err(anyhow!("Library projects must be packaged"));
@@ -880,11 +867,7 @@ impl InitProjectKind {
880867
);
881868

882869
// Always include a build system if the project is packaged.
883-
let build_backend = match build_backend {
884-
Some(build_backend) => build_backend,
885-
None if preview.is_enabled() => ProjectBuildBackend::Uv,
886-
None => ProjectBuildBackend::Hatch,
887-
};
870+
let build_backend = build_backend.unwrap_or(ProjectBuildBackend::Uv);
888871
pyproject.push('\n');
889872
pyproject.push_str(&pyproject_build_system(name, build_backend));
890873
pyproject_build_backend_prerequisites(name, path, build_backend)?;

crates/uv/tests/it/build.rs

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,7 +1439,6 @@ fn build_fast_path() -> Result<()> {
14391439
let built_by_uv = current_dir()?.join("../../scripts/packages/built-by-uv");
14401440

14411441
uv_snapshot!(context.build()
1442-
.arg("--preview")
14431442
.arg(&built_by_uv)
14441443
.arg("--out-dir")
14451444
.arg(context.temp_dir.join("output1")), @r###"
@@ -1465,7 +1464,6 @@ fn build_fast_path() -> Result<()> {
14651464
.assert(predicate::path::is_file());
14661465

14671466
uv_snapshot!(context.build()
1468-
.arg("--preview")
14691467
.arg(&built_by_uv)
14701468
.arg("--out-dir")
14711469
.arg(context.temp_dir.join("output2"))
@@ -1485,7 +1483,6 @@ fn build_fast_path() -> Result<()> {
14851483
.assert(predicate::path::is_file());
14861484

14871485
uv_snapshot!(context.build()
1488-
.arg("--preview")
14891486
.arg(&built_by_uv)
14901487
.arg("--out-dir")
14911488
.arg(context.temp_dir.join("output3"))
@@ -1505,7 +1502,6 @@ fn build_fast_path() -> Result<()> {
15051502
.assert(predicate::path::is_file());
15061503

15071504
uv_snapshot!(context.build()
1508-
.arg("--preview")
15091505
.arg(&built_by_uv)
15101506
.arg("--out-dir")
15111507
.arg(context.temp_dir.join("output4"))
@@ -1545,7 +1541,6 @@ fn build_list_files() -> Result<()> {
15451541
// By default, we build the wheel from the source dist, which we need to do even for the list
15461542
// task.
15471543
uv_snapshot!(context.build()
1548-
.arg("--preview")
15491544
.arg(&built_by_uv)
15501545
.arg("--out-dir")
15511546
.arg(context.temp_dir.join("output1"))
@@ -1601,7 +1596,6 @@ fn build_list_files() -> Result<()> {
16011596
.assert(predicate::path::missing());
16021597

16031598
uv_snapshot!(context.build()
1604-
.arg("--preview")
16051599
.arg(&built_by_uv)
16061600
.arg("--out-dir")
16071601
.arg(context.temp_dir.join("output2"))
@@ -1670,7 +1664,6 @@ fn build_list_files_errors() -> Result<()> {
16701664
// In CI, we run with link mode settings.
16711665
filters.push(("--link-mode <LINK_MODE> ", ""));
16721666
uv_snapshot!(filters, context.build()
1673-
.arg("--preview")
16741667
.arg(&built_by_uv)
16751668
.arg("--out-dir")
16761669
.arg(context.temp_dir.join("output1"))
@@ -1694,7 +1687,6 @@ fn build_list_files_errors() -> Result<()> {
16941687
// Windows normalization
16951688
filters.push(("/crates/uv/../../", "/"));
16961689
uv_snapshot!(filters, context.build()
1697-
.arg("--preview")
16981690
.arg(&anyio_local)
16991691
.arg("--out-dir")
17001692
.arg(context.temp_dir.join("output2"))
@@ -1987,12 +1979,7 @@ fn force_pep517() -> Result<()> {
19871979
// We need to use a real `uv_build` package.
19881980
let context = TestContext::new("3.12").with_exclude_newer("2025-05-27T00:00:00Z");
19891981

1990-
context
1991-
.init()
1992-
.arg("--build-backend")
1993-
.arg("uv")
1994-
.assert()
1995-
.success();
1982+
context.init().assert().success();
19961983

19971984
let pyproject_toml = context.temp_dir.child("pyproject.toml");
19981985
pyproject_toml.write_str(indoc! {r#"
@@ -2026,7 +2013,7 @@ fn force_pep517() -> Result<()> {
20262013
20272014
----- stderr -----
20282015
Building source distribution...
2029-
Error: Missing module directory for `does_not_exist` in `src`. Found: `temp`
2016+
Error: Missing source directory at: `src`
20302017
× Failed to build `[TEMP_DIR]/`
20312018
├─▶ The build backend returned an error
20322019
╰─▶ Call to `uv_build.build_sdist` failed (exit status: 1)

crates/uv/tests/it/build_backend.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,7 @@ fn preserve_executable_bit() -> Result<()> {
222222
let project_dir = context.temp_dir.path().join("preserve_executable_bit");
223223
context
224224
.init()
225-
.arg("--build-backend")
226-
.arg("uv")
225+
.arg("--lib")
227226
.arg(&project_dir)
228227
.assert()
229228
.success();
@@ -296,7 +295,7 @@ fn rename_module() -> Result<()> {
296295
module-name = "bar"
297296
298297
[build-system]
299-
requires = ["uv_build>=0.5,<0.8"]
298+
requires = ["uv_build>=0.7,<10000"]
300299
build-backend = "uv_build"
301300
"#})?;
302301

@@ -377,7 +376,7 @@ fn rename_module_editable_build() -> Result<()> {
377376
module-name = "bar"
378377
379378
[build-system]
380-
requires = ["uv_build>=0.5,<0.8"]
379+
requires = ["uv_build>=0.7,<10000"]
381380
build-backend = "uv_build"
382381
"#})?;
383382

@@ -436,7 +435,7 @@ fn build_module_name_normalization() -> Result<()> {
436435
version = "1.0.0"
437436
438437
[build-system]
439-
requires = ["uv_build>=0.5,<0.8"]
438+
requires = ["uv_build>=0.7,<10000"]
440439
build-backend = "uv_build"
441440
442441
[tool.uv.build-backend]
@@ -548,7 +547,7 @@ fn build_sdist_with_long_path() -> Result<()> {
548547
version = "1.0.0"
549548
550549
[build-system]
551-
requires = ["uv_build>=0.7,<0.8"]
550+
requires = ["uv_build>=0.7,<10000"]
552551
build-backend = "uv_build"
553552
"#})?;
554553
context
@@ -591,7 +590,7 @@ fn sdist_error_without_module() -> Result<()> {
591590
version = "1.0.0"
592591
593592
[build-system]
594-
requires = ["uv_build>=0.7,<0.8"]
593+
requires = ["uv_build>=0.7,<10000"]
595594
build-backend = "uv_build"
596595
"#})?;
597596

@@ -661,7 +660,7 @@ fn complex_namespace_packages() -> Result<()> {
661660
module-name = "{project_name_dist_info}.{part_name}"
662661
663662
[build-system]
664-
requires = ["uv_build>=0.5.15,<10000"]
663+
requires = ["uv_build>=0.7,<10000"]
665664
build-backend = "uv_build"
666665
"#
667666
};
@@ -770,8 +769,7 @@ fn symlinked_file() -> Result<()> {
770769
let project = context.temp_dir.child("project");
771770
context
772771
.init()
773-
.arg("--build-backend")
774-
.arg("uv")
772+
.arg("--lib")
775773
.arg(project.path())
776774
.assert()
777775
.success();
@@ -783,7 +781,7 @@ fn symlinked_file() -> Result<()> {
783781
license-files = ["LICENSE"]
784782
785783
[build-system]
786-
requires = ["uv_build>=0.5.15,<10000"]
784+
requires = ["uv_build>=0.7,<10000"]
787785
build-backend = "uv_build"
788786
"#
789787
})?;

crates/uv/tests/it/common/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,14 @@ impl TestContext {
664664
));
665665
// For wiremock tests
666666
filters.push((r"127\.0\.0\.1:\d*".to_string(), "[LOCALHOST]".to_string()));
667+
// Avoid breaking the tests when bumping the uv version
668+
filters.push((
669+
format!(
670+
r#"requires = \["uv_build>={},<[0-9.]+"\]"#,
671+
uv_version::version()
672+
),
673+
r#"requires = ["uv_build>=[CURRENT_VERSION],<[NEXT_BREAKING]"]"#.to_string(),
674+
));
667675

668676
Self {
669677
root: ChildPath::new(root.path()),

0 commit comments

Comments
 (0)