@@ -608,3 +608,103 @@ def test_detect_packages_from_files_mixed_init_and_source_bases() -> None:
608608 assert len (detected ) == 3 # noqa: PLR2004
609609 # Should have two parent directories
610610 assert len (parent_dirs ) == 2 # noqa: PLR2004
611+
612+
613+ def test_detect_packages_from_files_handles_mixed_packages_and_loose_files () -> None :
614+ """Test handling mix of package files and loose files."""
615+ with tempfile .TemporaryDirectory () as tmpdir :
616+ tmp_path = Path (tmpdir )
617+ # Package file
618+ pkg_dir = tmp_path / "mypkg"
619+ pkg_dir .mkdir ()
620+ (pkg_dir / "__init__.py" ).write_text ("" )
621+ pkg_file = pkg_dir / "module.py"
622+ pkg_file .write_text ("" )
623+
624+ # Loose file (no __init__.py, not under source_bases)
625+ loose_dir = tmp_path / "loose"
626+ loose_dir .mkdir ()
627+ loose_file = loose_dir / "script.py"
628+ loose_file .write_text ("" )
629+
630+ # --- execute ---
631+ detected , _parent_dirs = _modules .detect_packages_from_files (
632+ file_paths = [pkg_file , loose_file ],
633+ package_name = "default" ,
634+ )
635+
636+ # --- verify ---
637+ # Should detect "mypkg" and include "default" as fallback
638+ assert "mypkg" in detected
639+ assert "default" in detected
640+ assert len (detected ) == 2 # noqa: PLR2004
641+
642+
643+ def test_detect_packages_from_files_deterministic_output_order () -> None :
644+ """Test that function produces deterministic results (for build reproducibility)."""
645+ with tempfile .TemporaryDirectory () as tmpdir :
646+ tmp_path = Path (tmpdir )
647+ pkg1_dir = tmp_path / "pkg1"
648+ pkg1_dir .mkdir ()
649+ (pkg1_dir / "__init__.py" ).write_text ("" )
650+ file1 = pkg1_dir / "module1.py"
651+ file1 .write_text ("" )
652+
653+ pkg2_dir = tmp_path / "pkg2"
654+ pkg2_dir .mkdir ()
655+ (pkg2_dir / "__init__.py" ).write_text ("" )
656+ file2 = pkg2_dir / "module2.py"
657+ file2 .write_text ("" )
658+
659+ # --- execute ---
660+ # Call multiple times with different file order
661+ result1 , _parent_dirs1 = _modules .detect_packages_from_files (
662+ file_paths = [file1 , file2 ],
663+ package_name = "default" ,
664+ )
665+ result2 , _parent_dirs2 = _modules .detect_packages_from_files (
666+ file_paths = [file2 , file1 ],
667+ package_name = "default" ,
668+ )
669+
670+ # --- verify ---
671+ # Results should be identical (sets are unordered, but contents same)
672+ assert result1 == result2
673+ assert sorted (result1 ) == sorted (result2 )
674+
675+
676+ def test_detect_packages_from_files_source_bases_only_applies_to_files_under_base () -> (
677+ None
678+ ):
679+ """Test that source_bases only applies to files under the base, not elsewhere."""
680+ with tempfile .TemporaryDirectory () as tmpdir :
681+ tmp_path = Path (tmpdir )
682+ src_dir = tmp_path / "src"
683+ src_dir .mkdir ()
684+ # File under source_bases (should use source_bases logic)
685+ pkg1_dir = src_dir / "pkg1"
686+ pkg1_dir .mkdir ()
687+ file1 = pkg1_dir / "module1.py"
688+ file1 .write_text ("" )
689+
690+ # File outside source_bases (should require __init__.py)
691+ other_dir = tmp_path / "other"
692+ other_dir .mkdir ()
693+ pkg2_dir = other_dir / "pkg2"
694+ pkg2_dir .mkdir ()
695+ # No __init__.py, so should not be detected
696+ file2 = pkg2_dir / "module2.py"
697+ file2 .write_text ("" )
698+
699+ # --- execute ---
700+ detected , _parent_dirs = _modules .detect_packages_from_files (
701+ file_paths = [file1 , file2 ],
702+ package_name = "default" ,
703+ source_bases = [str (src_dir )],
704+ )
705+
706+ # --- verify ---
707+ # Should detect "pkg1" via source_bases, but not "pkg2" (outside base)
708+ assert "pkg1" in detected
709+ assert "pkg2" not in detected
710+ assert "default" in detected
0 commit comments