@@ -7,7 +7,7 @@ use indoc::indoc;
77
88use uv_python:: PYTHON_VERSION_FILENAME ;
99
10- use common:: { uv_snapshot, TestContext } ;
10+ use common:: { copy_dir_all , uv_snapshot, TestContext } ;
1111
1212mod common;
1313
@@ -538,6 +538,141 @@ fn run_with() -> Result<()> {
538538 Ok ( ( ) )
539539}
540540
541+ #[ test]
542+ fn run_with_editable ( ) -> Result < ( ) > {
543+ let context = TestContext :: new ( "3.12" ) ;
544+
545+ let anyio_local = context. temp_dir . child ( "src" ) . child ( "anyio_local" ) ;
546+ copy_dir_all (
547+ context. workspace_root . join ( "scripts/packages/anyio_local" ) ,
548+ & anyio_local,
549+ ) ?;
550+
551+ let black_editable = context. temp_dir . child ( "src" ) . child ( "black_editable" ) ;
552+ copy_dir_all (
553+ context
554+ . workspace_root
555+ . join ( "scripts/packages/black_editable" ) ,
556+ & black_editable,
557+ ) ?;
558+
559+ let pyproject_toml = context. temp_dir . child ( "pyproject.toml" ) ;
560+ pyproject_toml. write_str ( indoc ! { r#"
561+ [project]
562+ name = "foo"
563+ version = "1.0.0"
564+ requires-python = ">=3.8"
565+ dependencies = ["anyio", "sniffio==1.3.1"]
566+ "#
567+ } ) ?;
568+
569+ let test_script = context. temp_dir . child ( "main.py" ) ;
570+ test_script. write_str ( indoc ! { r"
571+ import sniffio
572+ "
573+ } ) ?;
574+
575+ // Requesting an editable requirement should install it in a layer.
576+ uv_snapshot ! ( context. filters( ) , context. run( ) . arg( "--with-editable" ) . arg( "./src/black_editable" ) . arg( "main.py" ) , @r###"
577+ success: true
578+ exit_code: 0
579+ ----- stdout -----
580+
581+ ----- stderr -----
582+ Resolved 6 packages in [TIME]
583+ Prepared 4 packages in [TIME]
584+ Installed 4 packages in [TIME]
585+ + anyio==4.3.0
586+ + foo==1.0.0 (from file://[TEMP_DIR]/)
587+ + idna==3.6
588+ + sniffio==1.3.1
589+ Resolved 1 package in [TIME]
590+ Prepared 1 package in [TIME]
591+ Installed 1 package in [TIME]
592+ + black==0.1.0 (from file://[TEMP_DIR]/src/black_editable)
593+ "### ) ;
594+
595+ // Requesting an editable requirement should install it in a layer, even if it satisfied
596+ uv_snapshot ! ( context. filters( ) , context. run( ) . arg( "--with-editable" ) . arg( "./src/anyio_local" ) . arg( "main.py" ) , @r###"
597+ success: true
598+ exit_code: 0
599+ ----- stdout -----
600+
601+ ----- stderr -----
602+ Resolved 6 packages in [TIME]
603+ Audited 4 packages in [TIME]
604+ Resolved 1 package in [TIME]
605+ Prepared 1 package in [TIME]
606+ Installed 1 package in [TIME]
607+ + anyio==4.3.0+foo (from file://[TEMP_DIR]/src/anyio_local)
608+ "### ) ;
609+
610+ // Requesting the project itself should use the base environment.
611+ uv_snapshot ! ( context. filters( ) , context. run( ) . arg( "--with-editable" ) . arg( "." ) . arg( "main.py" ) , @r###"
612+ success: true
613+ exit_code: 0
614+ ----- stdout -----
615+
616+ ----- stderr -----
617+ Resolved 6 packages in [TIME]
618+ Audited 4 packages in [TIME]
619+ "### ) ;
620+
621+ // Similarly, an already editable requirement does not require a layer
622+ pyproject_toml. write_str ( indoc ! { r#"
623+ [project]
624+ name = "foo"
625+ version = "1.0.0"
626+ requires-python = ">=3.8"
627+ dependencies = ["anyio", "sniffio==1.3.1"]
628+
629+ [tool.uv.sources]
630+ anyio = { path = "./src/anyio_local", editable = true }
631+ "#
632+ } ) ?;
633+
634+ uv_snapshot ! ( context. filters( ) , context. sync( ) , @r###"
635+ success: true
636+ exit_code: 0
637+ ----- stdout -----
638+
639+ ----- stderr -----
640+ Resolved 3 packages in [TIME]
641+ Prepared 1 package in [TIME]
642+ Uninstalled 3 packages in [TIME]
643+ Installed 2 packages in [TIME]
644+ - anyio==4.3.0
645+ + anyio==4.3.0+foo (from file://[TEMP_DIR]/src/anyio_local)
646+ ~ foo==1.0.0 (from file://[TEMP_DIR]/)
647+ - idna==3.6
648+ "### ) ;
649+
650+ uv_snapshot ! ( context. filters( ) , context. run( ) . arg( "--with-editable" ) . arg( "./src/anyio_local" ) . arg( "main.py" ) , @r###"
651+ success: true
652+ exit_code: 0
653+ ----- stdout -----
654+
655+ ----- stderr -----
656+ Resolved 3 packages in [TIME]
657+ Audited 3 packages in [TIME]
658+ "### ) ;
659+
660+ // If invalid, we should reference `--with-editable`.
661+ uv_snapshot ! ( context. filters( ) , context. run( ) . arg( "--with" ) . arg( "./foo" ) . arg( "main.py" ) , @r###"
662+ success: false
663+ exit_code: 1
664+ ----- stdout -----
665+
666+ ----- stderr -----
667+ Resolved 3 packages in [TIME]
668+ Audited 3 packages in [TIME]
669+ × Invalid `--with` requirement
670+ ╰─▶ Distribution not found at: file://[TEMP_DIR]/foo
671+ "### ) ;
672+
673+ Ok ( ( ) )
674+ }
675+
541676#[ test]
542677fn run_locked ( ) -> Result < ( ) > {
543678 let context = TestContext :: new ( "3.12" ) ;
0 commit comments