ComfyUI-Manager/tests/common/pip_util/test_environment_recovery.py
Dr.Lt.Data 2866193baf ● feat: Draft pip package policy management system (not yet integrated)
Add comprehensive pip dependency conflict resolution framework as draft implementation. This is self-contained and does not affect existing
ComfyUI Manager functionality.

Key components:
- pip_util.py with PipBatch class for policy-driven package management
- Lazy-loaded policy system supporting base + user overrides
- Multi-stage policy execution (uninstall → apply_first_match → apply_all_matches → restore)
- Conditional policies based on platform, installed packages, and ComfyUI version
- Comprehensive test suite covering edge cases, workflows, and platform scenarios
- Design and implementation documentation

Policy capabilities (draft):
- Package replacement (e.g., PIL → Pillow, opencv-python → opencv-contrib-python)
- Version pinning to prevent dependency conflicts
- Dependency protection during installations
- Platform-specific handling (Linux/Windows, GPU detection)
- Pre-removal and post-restoration workflows

Testing infrastructure:
- Pytest-based test suite with isolated environments
- Dependency analysis tools for conflict detection
- Coverage for policy priority, edge cases, and environment recovery

Status: Draft implementation complete, integration with manager workflows pending.
2025-10-04 08:55:59 +09:00

159 lines
5.1 KiB
Python

"""
Test environment corruption and recovery (Priority 1)
Tests that packages deleted or modified during installation are restored
"""
import json
from pathlib import Path
import pytest
@pytest.fixture
def restore_policy(temp_policy_dir):
"""Create policy with restore section for lightweight packages"""
policy_content = {
"six": {
"restore": [
{
"target": "six",
"version": "1.16.0",
"reason": "six must be maintained at 1.16.0 for compatibility"
}
]
}
}
policy_file = temp_policy_dir / "pip-policy.json"
policy_file.write_text(json.dumps(policy_content, indent=2))
return policy_file
@pytest.mark.integration
def test_package_deletion_and_restore(
restore_policy,
mock_manager_util,
mock_context,
reset_test_venv,
get_installed_packages,
install_packages,
uninstall_packages
):
"""
Test package deleted by installation is restored
Priority: 1 (Essential)
Purpose:
Verify that when a package installation deletes another package,
the restore policy can bring it back with the correct version.
Based on DEPENDENCY_TREE_CONTEXT.md:
six==1.16.0 must be maintained for compatibility
After deletion, should restore to exactly 1.16.0
"""
from comfyui_manager.common.pip_util import PipBatch
# Verify six is initially installed at expected version
initial = get_installed_packages()
assert "six" in initial
assert initial["six"] == "1.16.0", f"Expected six==1.16.0, got {initial['six']}"
with PipBatch() as batch:
# Manually remove six to simulate deletion by another package
uninstall_packages("six")
# Check six was deleted
installed_after_delete = batch._get_installed_packages()
assert "six" not in installed_after_delete, "six should be deleted"
# Restore six
restored = batch.ensure_installed()
final_packages = batch._get_installed_packages()
# Verify six was restored to EXACT required version (not latest)
assert "six" in restored, "six should be in restored list"
assert final_packages["six"] == "1.16.0", \
"six should be restored to exact version 1.16.0 (not 1.17.0 latest)"
@pytest.fixture
def version_change_policy(temp_policy_dir):
"""Create policy for version change test with real packages"""
policy_content = {
"urllib3": {
"restore": [
{
"condition": {
"type": "installed",
"spec": "!=1.26.15"
},
"target": "urllib3",
"version": "1.26.15",
"reason": "urllib3 must be 1.26.15 for compatibility"
}
]
}
}
policy_file = temp_policy_dir / "pip-policy.json"
policy_file.write_text(json.dumps(policy_content, indent=2))
return policy_file
@pytest.mark.integration
def test_version_change_and_restore(
version_change_policy,
mock_manager_util,
mock_context,
reset_test_venv,
get_installed_packages,
install_packages
):
"""
Test package version changed by installation is restored
Priority: 1 (Essential)
Purpose:
Verify that when a package installation changes another package's
version, the restore policy can revert it to the required version.
Based on DEPENDENCY_TREE_CONTEXT.md:
urllib3 can upgrade from 1.26.15 (1.x) to 2.5.0 (2.x)
Restore policy with condition "!=1.26.15" should downgrade back
This tests downgrade capability (not just upgrade prevention)
"""
from comfyui_manager.common.pip_util import PipBatch
# Verify urllib3 1.26.15 is installed
initial = get_installed_packages()
assert "urllib3" in initial
assert initial["urllib3"] == "1.26.15", f"Expected urllib3==1.26.15, got {initial['urllib3']}"
with PipBatch() as batch:
# Manually upgrade urllib3 to 2.x to simulate version change
# This is a MAJOR version upgrade (1.x → 2.x)
install_packages("urllib3==2.1.0")
installed_after = batch._get_installed_packages()
# Verify version was changed to 2.x
assert installed_after["urllib3"] == "2.1.0", \
f"urllib3 should be upgraded to 2.1.0, got {installed_after['urllib3']}"
assert installed_after["urllib3"].startswith("2."), \
"urllib3 should be at 2.x series"
# Restore urllib3 to 1.26.15 (this is a DOWNGRADE from 2.x to 1.x)
restored = batch.ensure_installed()
final = batch._get_installed_packages()
# Verify condition was satisfied (2.1.0 != 1.26.15) and restore was triggered
assert "urllib3" in restored, "urllib3 should be in restored list"
# Verify version was DOWNGRADED from 2.x back to 1.x
assert final["urllib3"] == "1.26.15", \
"urllib3 should be downgraded to 1.26.15 (from 2.1.0)"
assert final["urllib3"].startswith("1."), \
f"urllib3 should be back at 1.x series, got {final['urllib3']}"