|
| 1 | +import json |
1 | 2 | import logging |
| 3 | +import os |
| 4 | +import platform |
| 5 | +import subprocess |
| 6 | +import sys |
| 7 | +from importlib.metadata import distributions |
| 8 | +from unittest.mock import MagicMock, patch |
2 | 9 |
|
3 | 10 | import pytest |
4 | 11 | from rich.logging import RichHandler |
@@ -206,3 +213,215 @@ def test_named_logger_doesnt_propagate(tmp_path, capsys): |
206 | 213 | assert "PQ&*" not in captured.out, ( |
207 | 214 | "logger writing to stdout through root handler" |
208 | 215 | ) |
| 216 | + |
| 217 | + |
| 218 | +@pytest.mark.parametrize("boolean, operator", [(True, True), (False, False)]) |
| 219 | +def test_python_version_header(boolean, operator, tmp_path): |
| 220 | + ver_header = f"{lateral_separator} PYTHON VERSION {lateral_separator}\n" |
| 221 | + |
| 222 | + fancylog.start_logging(tmp_path, fancylog, write_python=boolean) |
| 223 | + |
| 224 | + log_file = next(tmp_path.glob("*.log")) |
| 225 | + |
| 226 | + with open(log_file) as file: |
| 227 | + assert (ver_header in file.read()) == operator |
| 228 | + |
| 229 | + |
| 230 | +def test_correct_python_version_logged(tmp_path): |
| 231 | + """Python version logged should be equal to |
| 232 | + the output of platform.python_version(). |
| 233 | + """ |
| 234 | + |
| 235 | + fancylog.start_logging(tmp_path, fancylog, write_python=True) |
| 236 | + |
| 237 | + log_file = next(tmp_path.glob("*.log")) |
| 238 | + |
| 239 | + # Test logged python version is equal to platform.python_version() |
| 240 | + with open(log_file) as file: |
| 241 | + assert f"Python version: {platform.python_version()}" in file.read() |
| 242 | + |
| 243 | + |
| 244 | +@pytest.mark.parametrize("boolean, operator", [(True, True), (False, False)]) |
| 245 | +def test_environment_header(boolean, operator, tmp_path): |
| 246 | + ver_header = f"{lateral_separator} ENVIRONMENT {lateral_separator}\n" |
| 247 | + |
| 248 | + fancylog.start_logging(tmp_path, fancylog, write_env_packages=boolean) |
| 249 | + |
| 250 | + log_file = next(tmp_path.glob("*.log")) |
| 251 | + |
| 252 | + with open(log_file) as file: |
| 253 | + assert (ver_header in file.read()) == operator |
| 254 | + |
| 255 | + |
| 256 | +def test_correct_pkg_version_logged(tmp_path): |
| 257 | + """Package versions logged should be equal to |
| 258 | + the output of `conda list` or `pip list`. |
| 259 | + """ |
| 260 | + fancylog.start_logging(tmp_path, fancylog, write_env_packages=True) |
| 261 | + |
| 262 | + log_file = next(tmp_path.glob("*.log")) |
| 263 | + |
| 264 | + try: |
| 265 | + # If there is a conda environment, assert that the correct |
| 266 | + # version is logged for all pkgs |
| 267 | + conda_exe = os.environ["CONDA_EXE"] |
| 268 | + conda_list = subprocess.run( |
| 269 | + [conda_exe, "list", "--json"], capture_output=True, text=True |
| 270 | + ) |
| 271 | + |
| 272 | + conda_pkgs = json.loads(conda_list.stdout) |
| 273 | + for pkg in conda_pkgs: |
| 274 | + assert f"{pkg['name']:20} {pkg['version']:15}\n" |
| 275 | + |
| 276 | + except KeyError: |
| 277 | + # If there is no conda environment, assert that the correct |
| 278 | + # version is logged for all packages logged with pip list |
| 279 | + with open(log_file) as file: |
| 280 | + file_content = file.read() |
| 281 | + |
| 282 | + # Test local environment versions |
| 283 | + local_site_packages = next( |
| 284 | + p for p in sys.path if "site-packages" in p |
| 285 | + ) |
| 286 | + |
| 287 | + for dist in distributions(): |
| 288 | + if str(dist.locate_file("")).startswith(local_site_packages): |
| 289 | + assert ( |
| 290 | + f"{dist.metadata['Name']:20} {dist.version}" |
| 291 | + in file_content |
| 292 | + ) |
| 293 | + |
| 294 | + |
| 295 | +def test_mock_pip_pkgs(tmp_path): |
| 296 | + """Mock pip list subprocess |
| 297 | + and test that packages are logged correctly. |
| 298 | + """ |
| 299 | + |
| 300 | + # Simulated `pip list --json` output |
| 301 | + fake_pip_output = json.dumps( |
| 302 | + [ |
| 303 | + {"name": "fancylog", "version": "1.1.1", "location": "fake_env"}, |
| 304 | + {"name": "pytest", "version": "1.1.1", "location": "global_env"}, |
| 305 | + ] |
| 306 | + ) |
| 307 | + |
| 308 | + # Patch the environment and subprocess |
| 309 | + with ( |
| 310 | + patch.dict(os.environ, {}, clear=False), |
| 311 | + patch("os.getenv") as mock_getenv, |
| 312 | + patch("subprocess.run") as mock_run, |
| 313 | + ): |
| 314 | + # Eliminate conda environment packages triggers logging pip list |
| 315 | + os.environ.pop("CONDA_PREFIX", None) |
| 316 | + os.environ.pop("CONDA_EXE", None) |
| 317 | + |
| 318 | + mock_getenv.return_value = "fake_env" |
| 319 | + |
| 320 | + # Mocked subprocess result |
| 321 | + mock_run.return_value = MagicMock(stdout=fake_pip_output, returncode=0) |
| 322 | + |
| 323 | + fancylog.start_logging(tmp_path, fancylog, write_env_packages=True) |
| 324 | + |
| 325 | + log_file = next(tmp_path.glob("*.log")) |
| 326 | + |
| 327 | + # Log contains conda subheaders and mocked pkgs versions |
| 328 | + with open(log_file) as file: |
| 329 | + file_content = file.read() |
| 330 | + |
| 331 | + assert ( |
| 332 | + "No conda environment found, reporting pip packages" |
| 333 | + ) in file_content |
| 334 | + |
| 335 | + assert f"{'fancylog':20} {'1.1.1'}" |
| 336 | + assert f"{'pytest':20} {'1.1.1'}" |
| 337 | + |
| 338 | + |
| 339 | +def test_mock_conda_pkgs(tmp_path): |
| 340 | + """Mock conda environment variables |
| 341 | + and test that packages are logged correctly. |
| 342 | + """ |
| 343 | + |
| 344 | + fake_conda_env_name = "test_env" |
| 345 | + fake_conda_prefix = os.path.join( |
| 346 | + "path", "conda", "envs", fake_conda_env_name |
| 347 | + ) |
| 348 | + fake_conda_exe = os.path.join("fake", "conda") |
| 349 | + |
| 350 | + # Simulated `conda list --json` output |
| 351 | + fake_conda_output = json.dumps( |
| 352 | + [ |
| 353 | + {"name": "fancylog", "version": "1.1.1"}, |
| 354 | + {"name": "pytest", "version": "1.1.1"}, |
| 355 | + ] |
| 356 | + ) |
| 357 | + |
| 358 | + # Patch the environment and subprocess |
| 359 | + with ( |
| 360 | + patch.dict( |
| 361 | + os.environ, |
| 362 | + {"CONDA_PREFIX": fake_conda_prefix, "CONDA_EXE": fake_conda_exe}, |
| 363 | + ), |
| 364 | + patch("subprocess.run") as mock_run, |
| 365 | + ): |
| 366 | + # Mocked subprocess result |
| 367 | + mock_run.return_value = MagicMock( |
| 368 | + stdout=fake_conda_output, returncode=0 |
| 369 | + ) |
| 370 | + |
| 371 | + fancylog.start_logging(tmp_path, fancylog, write_env_packages=True) |
| 372 | + |
| 373 | + log_file = next(tmp_path.glob("*.log")) |
| 374 | + |
| 375 | + # Log contains conda subheaders and mocked pkgs versions |
| 376 | + with open(log_file) as file: |
| 377 | + file_content = file.read() |
| 378 | + |
| 379 | + assert "Conda environment:" in file_content |
| 380 | + assert "Environment packages (conda):" in file_content |
| 381 | + assert f"{'fancylog':20} {'1.1.1'}" |
| 382 | + assert f"{'pytest':20} {'1.1.1'}" |
| 383 | + |
| 384 | + |
| 385 | +def test_mock_no_environment(tmp_path): |
| 386 | + """Mock lack of any environment, |
| 387 | + and test that packages are logged correctly. |
| 388 | + """ |
| 389 | + |
| 390 | + # Simulated `pip list --json` output |
| 391 | + fake_pip_output = json.dumps( |
| 392 | + [ |
| 393 | + {"name": "fancylog", "version": "1.1.1", "location": "fake_env"}, |
| 394 | + {"name": "pytest", "version": "1.1.1", "location": "global_env"}, |
| 395 | + ] |
| 396 | + ) |
| 397 | + |
| 398 | + # Patch the environment and subprocess |
| 399 | + with ( |
| 400 | + patch.dict(os.environ, {}, clear=False), |
| 401 | + patch("os.getenv") as mock_getenv, |
| 402 | + patch("subprocess.run") as mock_run, |
| 403 | + ): |
| 404 | + # Eliminate conda environment packages triggers logging pip list |
| 405 | + os.environ.pop("CONDA_PREFIX", None) |
| 406 | + os.environ.pop("CONDA_EXE", None) |
| 407 | + |
| 408 | + # Mock lack of any local environment |
| 409 | + mock_getenv.return_value = None |
| 410 | + |
| 411 | + # Mocked subprocess result |
| 412 | + mock_run.return_value = MagicMock(stdout=fake_pip_output, returncode=0) |
| 413 | + |
| 414 | + fancylog.start_logging(tmp_path, fancylog, write_env_packages=True) |
| 415 | + |
| 416 | + log_file = next(tmp_path.glob("*.log")) |
| 417 | + |
| 418 | + # Log contains conda subheaders and mocked pkgs versions |
| 419 | + with open(log_file) as file: |
| 420 | + file_content = file.read() |
| 421 | + |
| 422 | + assert ( |
| 423 | + "No environment found, reporting global pip packages" |
| 424 | + ) in file_content |
| 425 | + |
| 426 | + assert f"{'fancylog':20} {'1.1.1'}" |
| 427 | + assert f"{'pytest':20} {'1.1.1'}" |
0 commit comments