@@ -5506,76 +5506,200 @@ fn add_git_to_script() -> Result<()> {
55065506 Ok ( ( ) )
55075507}
55085508
5509- /// Revert changes to a `pyproject.toml` the `add` fails.
5509+ /// Revert changes to the `pyproject.toml` and `uv.lock` when the `add` operation fails.
55105510#[ test]
55115511fn fail_to_add_revert_project ( ) -> Result < ( ) > {
55125512 let context = TestContext :: new ( "3.12" ) ;
55135513
5514- let pyproject_toml = context. temp_dir . child ( "pyproject.toml" ) ;
5515- pyproject_toml. write_str ( indoc ! { r#"
5514+ context
5515+ . temp_dir
5516+ . child ( "pyproject.toml" )
5517+ . write_str ( indoc ! { r#"
55165518 [project]
5517- name = "project "
5519+ name = "parent "
55185520 version = "0.1.0"
55195521 requires-python = ">=3.12"
55205522 dependencies = []
5523+ "# } ) ?;
5524+
5525+ // Add a dependency on a package that declares static metadata (so can always resolve), but
5526+ // can't be installed.
5527+ let pyproject_toml = context. temp_dir . child ( "child/pyproject.toml" ) ;
5528+ pyproject_toml. write_str ( indoc ! { r#"
5529+ [project]
5530+ name = "child"
5531+ version = "0.1.0"
5532+ requires-python = ">=3.12"
5533+ dependencies = ["iniconfig"]
55215534
55225535 [build-system]
55235536 requires = ["setuptools>=42"]
55245537 build-backend = "setuptools.build_meta"
55255538 "# } ) ?;
5539+ context
5540+ . temp_dir
5541+ . child ( "src" )
5542+ . child ( "child" )
5543+ . child ( "__init__.py" )
5544+ . touch ( ) ?;
5545+ context
5546+ . temp_dir
5547+ . child ( "child" )
5548+ . child ( "setup.py" )
5549+ . write_str ( "1/0" ) ?;
55265550
5527- // Adding `pytorch==1.0.2` should produce an error
5528- let filters = std:: iter:: once ( ( r"exit code: 1" , "exit status: 1" ) )
5529- . chain ( context. filters ( ) )
5530- . collect :: < Vec < _ > > ( ) ;
5531- uv_snapshot ! ( filters, context. add( ) . arg( "pytorch==1.0.2" ) , @r###"
5551+ uv_snapshot ! ( context. filters( ) , context. add( ) . arg( "./child" ) , @r###"
55325552 success: false
55335553 exit_code: 2
55345554 ----- stdout -----
55355555
55365556 ----- stderr -----
5537- Resolved 2 packages in [TIME]
5557+ Resolved 3 packages in [TIME]
55385558 error: Failed to prepare distributions
5539- Caused by: Failed to download and build `pytorch==1.0.2 `
5540- Caused by: Build backend failed to build wheel through `build_wheel` (exit status: 1)
5559+ Caused by: Failed to build `child @ file://[TEMP_DIR]/child `
5560+ Caused by: Build backend failed to determine requirements with `build_wheel() ` (exit status: 1)
55415561
55425562 [stderr]
55435563 Traceback (most recent call last):
5544- File "<string>", line 11 , in <module>
5545- File "[CACHE_DIR]/builds-v0/[TMP]/build_meta.py", line 410 , in build_wheel
5546- return self._build_with_temp_dir(
5547- ^^^^^^^^^^^^^^^^^^^^^^^^^^
5548- File "[CACHE_DIR]/builds-v0/[TMP]/build_meta.py", line 395 , in _build_with_temp_dir
5564+ File "<string>", line 14 , in <module>
5565+ File "[CACHE_DIR]/builds-v0/[TMP]/build_meta.py", line 325 , in get_requires_for_build_wheel
5566+ return self._get_build_requires(config_settings, requirements=['wheel'])
5567+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5568+ File "[CACHE_DIR]/builds-v0/[TMP]/build_meta.py", line 295 , in _get_build_requires
55495569 self.run_setup()
5550- File "[CACHE_DIR]/builds-v0/[TMP]/build_meta.py", line 487, in run_setup
5551- super().run_setup(setup_script=setup_script)
55525570 File "[CACHE_DIR]/builds-v0/[TMP]/build_meta.py", line 311, in run_setup
55535571 exec(code, locals())
5554- File "<string>", line 15, in <module>
5555- Exception: You tried to install "pytorch". The package named for PyTorch is "torch"
5556-
5572+ File "<string>", line 1, in <module>
5573+ ZeroDivisionError: division by zero
55575574 "### ) ;
55585575
5559- let pyproject_toml = context. read ( "pyproject.toml" ) ;
5576+ let pyproject_toml = fs_err :: read_to_string ( context. temp_dir . join ( "pyproject.toml" ) ) ? ;
55605577
55615578 insta:: with_settings!( {
55625579 filters => context. filters( ) ,
55635580 } , {
55645581 assert_snapshot!(
55655582 pyproject_toml, @r###"
55665583 [project]
5567- name = "project"
5584+ name = "parent"
5585+ version = "0.1.0"
5586+ requires-python = ">=3.12"
5587+ dependencies = []
5588+ "###
5589+ ) ;
5590+ } ) ;
5591+
5592+ // The lockfile should not exist, even though resolution succeeded.
5593+ assert ! ( !context. temp_dir. join( "uv.lock" ) . exists( ) ) ;
5594+
5595+ Ok ( ( ) )
5596+ }
5597+
5598+ /// Revert changes to the `pyproject.toml` and `uv.lock` when the `add` operation fails.
5599+ ///
5600+ /// In this case, the project has an existing lockfile.
5601+ #[ test]
5602+ fn fail_to_edit_revert_project ( ) -> Result < ( ) > {
5603+ let context = TestContext :: new ( "3.12" ) ;
5604+
5605+ context
5606+ . temp_dir
5607+ . child ( "pyproject.toml" )
5608+ . write_str ( indoc ! { r#"
5609+ [project]
5610+ name = "parent"
55685611 version = "0.1.0"
55695612 requires-python = ">=3.12"
55705613 dependencies = []
5614+ "# } ) ?;
5615+
5616+ uv_snapshot ! ( context. filters( ) , context. add( ) . arg( "iniconfig" ) , @r###"
5617+ success: true
5618+ exit_code: 0
5619+ ----- stdout -----
5620+
5621+ ----- stderr -----
5622+ Resolved 2 packages in [TIME]
5623+ Prepared 1 package in [TIME]
5624+ Installed 1 package in [TIME]
5625+ + iniconfig==2.0.0
5626+ "### ) ;
5627+
5628+ let before = fs_err:: read_to_string ( context. temp_dir . join ( "uv.lock" ) ) ?;
5629+
5630+ // Add a dependency on a package that declares static metadata (so can always resolve), but
5631+ // can't be installed.
5632+ let pyproject_toml = context. temp_dir . child ( "child/pyproject.toml" ) ;
5633+ pyproject_toml. write_str ( indoc ! { r#"
5634+ [project]
5635+ name = "child"
5636+ version = "0.1.0"
5637+ requires-python = ">=3.12"
5638+ dependencies = ["iniconfig"]
55715639
55725640 [build-system]
55735641 requires = ["setuptools>=42"]
55745642 build-backend = "setuptools.build_meta"
5643+ "# } ) ?;
5644+ context
5645+ . temp_dir
5646+ . child ( "src" )
5647+ . child ( "child" )
5648+ . child ( "__init__.py" )
5649+ . touch ( ) ?;
5650+ context
5651+ . temp_dir
5652+ . child ( "child" )
5653+ . child ( "setup.py" )
5654+ . write_str ( "1/0" ) ?;
5655+
5656+ uv_snapshot ! ( context. filters( ) , context. add( ) . arg( "./child" ) , @r###"
5657+ success: false
5658+ exit_code: 2
5659+ ----- stdout -----
5660+
5661+ ----- stderr -----
5662+ Resolved 3 packages in [TIME]
5663+ error: Failed to prepare distributions
5664+ Caused by: Failed to build `child @ file://[TEMP_DIR]/child`
5665+ Caused by: Build backend failed to determine requirements with `build_wheel()` (exit status: 1)
5666+
5667+ [stderr]
5668+ Traceback (most recent call last):
5669+ File "<string>", line 14, in <module>
5670+ File "[CACHE_DIR]/builds-v0/[TMP]/build_meta.py", line 325, in get_requires_for_build_wheel
5671+ return self._get_build_requires(config_settings, requirements=['wheel'])
5672+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5673+ File "[CACHE_DIR]/builds-v0/[TMP]/build_meta.py", line 295, in _get_build_requires
5674+ self.run_setup()
5675+ File "[CACHE_DIR]/builds-v0/[TMP]/build_meta.py", line 311, in run_setup
5676+ exec(code, locals())
5677+ File "<string>", line 1, in <module>
5678+ ZeroDivisionError: division by zero
5679+ "### ) ;
5680+
5681+ let pyproject_toml = fs_err:: read_to_string ( context. temp_dir . join ( "pyproject.toml" ) ) ?;
5682+
5683+ insta:: with_settings!( {
5684+ filters => context. filters( ) ,
5685+ } , {
5686+ assert_snapshot!(
5687+ pyproject_toml, @r###"
5688+ [project]
5689+ name = "parent"
5690+ version = "0.1.0"
5691+ requires-python = ">=3.12"
5692+ dependencies = [
5693+ "iniconfig>=2.0.0",
5694+ ]
55755695 "###
55765696 ) ;
55775697 } ) ;
55785698
5699+ // The lockfile should exist, but be unchanged.
5700+ let after = fs_err:: read_to_string ( context. temp_dir . join ( "uv.lock" ) ) ?;
5701+ assert_eq ! ( before, after) ;
5702+
55795703 Ok ( ( ) )
55805704}
55815705
0 commit comments