test_check_init_py.py
1 import subprocess 2 import sys 3 from pathlib import Path 4 5 import pytest 6 7 8 def get_check_init_py_script() -> Path: 9 return Path(__file__).resolve().parents[2] / "dev" / "check_init_py.py" 10 11 12 @pytest.fixture 13 def temp_git_repo(tmp_path: Path) -> Path: 14 subprocess.check_call(["git", "init"], cwd=tmp_path) 15 subprocess.check_call(["git", "config", "user.email", "test@example.com"], cwd=tmp_path) 16 subprocess.check_call(["git", "config", "user.name", "Test User"], cwd=tmp_path) 17 return tmp_path 18 19 20 def test_exits_with_0_when_all_directories_have_init_py(temp_git_repo: Path) -> None: 21 mlflow_dir = temp_git_repo / "mlflow" 22 test_package_dir = mlflow_dir / "test_package" 23 test_package_dir.mkdir(parents=True) 24 25 (mlflow_dir / "__init__.py").touch() 26 (test_package_dir / "__init__.py").touch() 27 (test_package_dir / "test_module.py").touch() 28 29 subprocess.check_call(["git", "add", "."], cwd=temp_git_repo) 30 subprocess.check_call(["git", "commit", "-m", "Initial commit"], cwd=temp_git_repo) 31 32 result = subprocess.run( 33 [sys.executable, get_check_init_py_script()], 34 capture_output=True, 35 text=True, 36 cwd=temp_git_repo, 37 ) 38 39 assert result.returncode == 0 40 assert result.stdout == "" 41 42 43 def test_exits_with_1_when_directories_missing_init_py(temp_git_repo: Path) -> None: 44 mlflow_dir = temp_git_repo / "mlflow" 45 test_package_dir = mlflow_dir / "test_package" 46 test_package_dir.mkdir(parents=True) 47 48 (test_package_dir / "test_module.py").touch() 49 50 subprocess.check_call(["git", "add", "."], cwd=temp_git_repo) 51 subprocess.check_call(["git", "commit", "-m", "Initial commit"], cwd=temp_git_repo) 52 53 result = subprocess.run( 54 [sys.executable, get_check_init_py_script()], 55 capture_output=True, 56 text=True, 57 cwd=temp_git_repo, 58 ) 59 60 assert result.returncode == 1 61 assert ( 62 "Error: The following directories contain Python files but lack __init__.py:" 63 in result.stdout 64 ) 65 assert "mlflow" in result.stdout 66 assert "mlflow/test_package" in result.stdout 67 68 69 def test_exits_with_0_when_no_python_files_exist(temp_git_repo: Path) -> None: 70 mlflow_dir = temp_git_repo / "mlflow" 71 js_dir = mlflow_dir / "server" / "js" 72 js_dir.mkdir(parents=True) 73 74 (js_dir / "main.js").touch() 75 76 subprocess.check_call(["git", "add", "."], cwd=temp_git_repo) 77 subprocess.check_call(["git", "commit", "-m", "Initial commit"], cwd=temp_git_repo) 78 79 result = subprocess.run( 80 [sys.executable, get_check_init_py_script()], 81 capture_output=True, 82 text=True, 83 cwd=temp_git_repo, 84 ) 85 86 assert result.returncode == 0 87 assert result.stdout == "" 88 89 90 def test_identifies_only_directories_missing_init_py(temp_git_repo: Path) -> None: 91 mlflow_dir = temp_git_repo / "mlflow" 92 package1_dir = mlflow_dir / "package1" 93 package2_dir = mlflow_dir / "package2" 94 package1_dir.mkdir(parents=True) 95 package2_dir.mkdir(parents=True) 96 97 (mlflow_dir / "__init__.py").touch() 98 (package1_dir / "__init__.py").touch() 99 100 (package1_dir / "module1.py").touch() 101 (package2_dir / "module2.py").touch() 102 103 subprocess.check_call(["git", "add", "."], cwd=temp_git_repo) 104 subprocess.check_call(["git", "commit", "-m", "Initial commit"], cwd=temp_git_repo) 105 106 result = subprocess.run( 107 [sys.executable, get_check_init_py_script()], 108 capture_output=True, 109 text=True, 110 cwd=temp_git_repo, 111 ) 112 113 assert result.returncode == 1 114 assert ( 115 "Error: The following directories contain Python files but lack __init__.py:" 116 in result.stdout 117 ) 118 assert "mlflow/package2" in result.stdout 119 assert "mlflow/package1" not in result.stdout 120 121 122 def test_checks_tests_directory_for_missing_init_py(temp_git_repo: Path) -> None: 123 tests_dir = temp_git_repo / "tests" 124 test_package_dir = tests_dir / "test_package" 125 test_package_dir.mkdir(parents=True) 126 127 # Only test files (starting with test_) are checked 128 (test_package_dir / "test_module.py").touch() 129 130 subprocess.check_call(["git", "add", "."], cwd=temp_git_repo) 131 subprocess.check_call(["git", "commit", "-m", "Initial commit"], cwd=temp_git_repo) 132 133 result = subprocess.run( 134 [sys.executable, get_check_init_py_script()], 135 capture_output=True, 136 text=True, 137 cwd=temp_git_repo, 138 ) 139 140 assert result.returncode == 1 141 assert ( 142 "Error: The following directories contain Python files but lack __init__.py:" 143 in result.stdout 144 ) 145 assert "tests/test_package" in result.stdout 146 assert "tests" in result.stdout # Parent directory also needs __init__.py 147 148 149 def test_exits_with_0_when_tests_directories_have_init_py(temp_git_repo: Path) -> None: 150 tests_dir = temp_git_repo / "tests" 151 test_package_dir = tests_dir / "test_package" 152 test_package_dir.mkdir(parents=True) 153 154 (tests_dir / "__init__.py").touch() 155 (test_package_dir / "__init__.py").touch() 156 (test_package_dir / "test_module.py").touch() 157 158 subprocess.check_call(["git", "add", "."], cwd=temp_git_repo) 159 subprocess.check_call(["git", "commit", "-m", "Initial commit"], cwd=temp_git_repo) 160 161 result = subprocess.run( 162 [sys.executable, get_check_init_py_script()], 163 capture_output=True, 164 text=True, 165 cwd=temp_git_repo, 166 ) 167 168 assert result.returncode == 0 169 assert result.stdout == "" 170 171 172 def test_ignores_non_test_files_in_tests_directory(temp_git_repo: Path) -> None: 173 tests_dir = temp_git_repo / "tests" 174 test_package_dir = tests_dir / "test_package" 175 test_package_dir.mkdir(parents=True) 176 177 # Non-test file (doesn't start with test_) should be ignored 178 (test_package_dir / "helper.py").touch() 179 (test_package_dir / "utils.py").touch() 180 181 subprocess.check_call(["git", "add", "."], cwd=temp_git_repo) 182 subprocess.check_call(["git", "commit", "-m", "Initial commit"], cwd=temp_git_repo) 183 184 result = subprocess.run( 185 [sys.executable, get_check_init_py_script()], 186 capture_output=True, 187 text=True, 188 cwd=temp_git_repo, 189 ) 190 191 # Should pass since no test files exist 192 assert result.returncode == 0 193 assert result.stdout == "" 194 195 196 def test_checks_all_parent_directories(temp_git_repo: Path) -> None: 197 mlflow_dir = temp_git_repo / "mlflow" 198 deep_dir = mlflow_dir / "level1" / "level2" / "level3" 199 deep_dir.mkdir(parents=True) 200 201 # Create a Python file deep in the hierarchy 202 (deep_dir / "module.py").touch() 203 204 # Only add __init__.py to some directories 205 (mlflow_dir / "__init__.py").touch() 206 (mlflow_dir / "level1" / "__init__.py").touch() 207 # Missing: level2 and level3 __init__.py files 208 209 subprocess.check_call(["git", "add", "."], cwd=temp_git_repo) 210 subprocess.check_call(["git", "commit", "-m", "Initial commit"], cwd=temp_git_repo) 211 212 result = subprocess.run( 213 [sys.executable, get_check_init_py_script()], 214 capture_output=True, 215 text=True, 216 cwd=temp_git_repo, 217 ) 218 219 assert result.returncode == 1 220 assert ( 221 "Error: The following directories contain Python files but lack __init__.py:" 222 in result.stdout 223 ) 224 # Both level2 and level3 should be reported as missing __init__.py 225 assert "mlflow/level1/level2" in result.stdout 226 assert "mlflow/level1/level2/level3" in result.stdout