@@ -487,3 +487,116 @@ def test_constraints_to_uv_filters_and_preserves_order():
487487def test_constraints_to_uv_empty_input ():
488488 assert _constraints_to_uv ([]) == []
489489 assert _constraints_to_uv (["\n " , "#" * 79 + "\n " , " \n " ]) == []
490+
491+
492+ def test_writes_constraint_dependencies (tmp_path , monkeypatch ):
493+ monkeypatch .chdir (tmp_path )
494+ hook = UvPyprojectUpdater ()
495+ (tmp_path / "mx.ini" ).write_text ("[settings]" )
496+ config = Configuration ("mx.ini" )
497+ state = State (config )
498+ state .constraints = [
499+ "# begin constraints from: https://example.com/a.txt\n " ,
500+ "Zope==6.0\n " ,
501+ "# AccessControl==7.3 -> mxdev disabled (source)\n " ,
502+ "# end constraints from: https://example.com/a.txt\n " ,
503+ ]
504+
505+ (tmp_path / "pyproject.toml" ).write_text (
506+ '[project]\n name = "test"\n dependencies = []\n \n [tool.uv]\n managed = true\n '
507+ )
508+
509+ hook .write (state )
510+
511+ content = (tmp_path / "pyproject.toml" ).read_text ()
512+ assert "# managed by mxdev - do not edit" in content
513+ assert "# begin constraints from: https://example.com/a.txt" in content
514+ assert "# AccessControl==7.3 -> mxdev disabled (source)" in content
515+ doc = tomlkit .parse (content )
516+ assert list (doc ["tool" ]["uv" ]["constraint-dependencies" ]) == ["Zope==6.0" ]
517+
518+
519+ def test_opt_out_disables_constraint_dependencies (tmp_path , monkeypatch ):
520+ monkeypatch .chdir (tmp_path )
521+ hook = UvPyprojectUpdater ()
522+ (tmp_path / "mx.ini" ).write_text ("[settings]\n uv-constraint-dependencies = false\n " )
523+ config = Configuration ("mx.ini" )
524+ state = State (config )
525+ state .constraints = ["Zope==6.0\n " ]
526+
527+ (tmp_path / "pyproject.toml" ).write_text (
528+ '[project]\n name = "test"\n dependencies = []\n \n [tool.uv]\n managed = true\n '
529+ )
530+
531+ hook .write (state )
532+
533+ doc = tomlkit .parse ((tmp_path / "pyproject.toml" ).read_text ())
534+ assert "constraint-dependencies" not in doc ["tool" ]["uv" ]
535+
536+
537+ def test_replaces_existing_constraint_dependencies (tmp_path , monkeypatch ):
538+ monkeypatch .chdir (tmp_path )
539+ hook = UvPyprojectUpdater ()
540+ (tmp_path / "mx.ini" ).write_text ("[settings]" )
541+ config = Configuration ("mx.ini" )
542+ state = State (config )
543+ state .constraints = ["Zope==6.0\n " ]
544+
545+ (tmp_path / "pyproject.toml" ).write_text (
546+ '[project]\n name = "test"\n dependencies = []\n \n '
547+ "[tool.uv]\n managed = true\n "
548+ 'constraint-dependencies = [\n "OldPin==0.0.1",\n ]\n '
549+ )
550+
551+ hook .write (state )
552+
553+ content = (tmp_path / "pyproject.toml" ).read_text ()
554+ assert "OldPin" not in content
555+ doc = tomlkit .parse (content )
556+ assert list (doc ["tool" ]["uv" ]["constraint-dependencies" ]) == ["Zope==6.0" ]
557+
558+
559+ def test_constraint_dependencies_idempotency (tmp_path , monkeypatch ):
560+ monkeypatch .chdir (tmp_path )
561+ hook = UvPyprojectUpdater ()
562+ (tmp_path / "mx.ini" ).write_text ("[settings]" )
563+ config = Configuration ("mx.ini" )
564+ state = State (config )
565+ state .constraints = [
566+ "# begin constraints from: https://example.com/a.txt\n " ,
567+ "Zope==6.0\n " ,
568+ "AccessControl==7.3\n " ,
569+ "# end constraints from: https://example.com/a.txt\n " ,
570+ ]
571+
572+ (tmp_path / "pyproject.toml" ).write_text (
573+ '[project]\n name = "test"\n dependencies = []\n \n [tool.uv]\n managed = true\n '
574+ )
575+
576+ hook .write (state )
577+ first = (tmp_path / "pyproject.toml" ).read_text ()
578+ hook .write (state )
579+ second = (tmp_path / "pyproject.toml" ).read_text ()
580+ assert first == second
581+
582+
583+ def test_empty_constraints_removes_stale_managed_array (tmp_path , monkeypatch ):
584+ monkeypatch .chdir (tmp_path )
585+ hook = UvPyprojectUpdater ()
586+ # A package ensures _update_pyproject does not early-return.
587+ mx_ini = "[settings]\n [pkg1]\n url = https://example.com/pkg1.git\n " "target = sources\n install-mode = editable\n "
588+ (tmp_path / "mx.ini" ).write_text (mx_ini )
589+ config = Configuration ("mx.ini" )
590+ state = State (config )
591+ state .constraints = [] # nothing resolved
592+
593+ (tmp_path / "pyproject.toml" ).write_text (
594+ '[project]\n name = "test"\n dependencies = []\n \n '
595+ "[tool.uv]\n managed = true\n "
596+ 'constraint-dependencies = [\n "StalePin==9.9.9",\n ]\n '
597+ )
598+
599+ hook .write (state )
600+
601+ doc = tomlkit .parse ((tmp_path / "pyproject.toml" ).read_text ())
602+ assert "constraint-dependencies" not in doc ["tool" ]["uv" ]
0 commit comments