ComfyUI-Manager/tests/common/pip_util/test_policy_priority.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

181 lines
4.9 KiB
Python

"""
Test policy priority and conflicts (Priority 2)
Tests that user policies override base policies correctly
"""
import json
import subprocess
from pathlib import Path
import pytest
@pytest.fixture
def conflicting_policies(temp_policy_dir, temp_user_policy_dir):
"""Create conflicting base and user policies"""
# Base policy
base_content = {
"numpy": {
"apply_first_match": [
{
"type": "skip",
"reason": "Base policy skip"
}
]
}
}
base_file = temp_policy_dir / "pip-policy.json"
base_file.write_text(json.dumps(base_content, indent=2))
# User policy (should override)
user_content = {
"numpy": {
"apply_first_match": [
{
"type": "force_version",
"version": "1.26.0",
"reason": "User override"
}
]
}
}
user_file = temp_user_policy_dir / "pip-policy.user.json"
user_file.write_text(json.dumps(user_content, indent=2))
return base_file, user_file
@pytest.mark.unit
def test_user_policy_overrides_base_policy(
conflicting_policies,
mock_manager_util,
mock_context,
mock_subprocess_success
):
"""
Test user policy completely replaces base policy
Priority: 2 (Important)
Purpose:
Verify that user policy completely overrides base policy
at the package level (not section-level merge).
"""
import sys
# Path setup handled by conftest.py
from comfyui_manager.common.pip_util import get_pip_policy
policy = get_pip_policy()
# Verify user policy replaced base policy
assert "numpy" in policy
assert "apply_first_match" in policy["numpy"]
assert len(policy["numpy"]["apply_first_match"]) == 1
# Should be force_version (user), not skip (base)
assert policy["numpy"]["apply_first_match"][0]["type"] == "force_version"
assert policy["numpy"]["apply_first_match"][0]["version"] == "1.26.0"
# Base policy skip should be completely gone
assert not any(
item["type"] == "skip"
for item in policy["numpy"]["apply_first_match"]
)
@pytest.fixture
def first_match_policy(temp_policy_dir):
"""Create policy with multiple apply_first_match entries"""
policy_content = {
"pkg": {
"apply_first_match": [
{
"condition": {
"type": "installed",
"package": "numpy"
},
"type": "force_version",
"version": "1.0"
},
{
"type": "force_version",
"version": "2.0"
},
{
"type": "skip"
}
]
}
}
policy_file = temp_policy_dir / "pip-policy.json"
policy_file.write_text(json.dumps(policy_content, indent=2))
return policy_file
@pytest.fixture
def mock_first_match_subprocess(monkeypatch):
"""Mock subprocess for first match test"""
call_sequence = []
installed_packages = {
"numpy": "1.26.0"
}
def mock_run(cmd, **kwargs):
call_sequence.append(cmd)
# pip freeze
if "freeze" in cmd:
output = "\n".join([f"{pkg}=={ver}" for pkg, ver in installed_packages.items()])
return subprocess.CompletedProcess(cmd, 0, output, "")
# pip install
if "install" in cmd and "pkg" in cmd:
if "pkg==1.0" in cmd:
installed_packages["pkg"] = "1.0"
return subprocess.CompletedProcess(cmd, 0, "", "")
return subprocess.CompletedProcess(cmd, 0, "", "")
monkeypatch.setattr("subprocess.run", mock_run)
return call_sequence, installed_packages
@pytest.mark.integration
def test_first_match_stops_at_first_satisfied(
first_match_policy,
mock_manager_util,
mock_context,
mock_first_match_subprocess
):
"""
Test apply_first_match stops at first satisfied condition
Priority: 2 (Important)
Purpose:
Verify that in apply_first_match, only the first policy
with a satisfied condition is executed (exclusive execution).
"""
import sys
# Path setup handled by conftest.py
from comfyui_manager.common.pip_util import PipBatch
call_sequence, installed_packages = mock_first_match_subprocess
with PipBatch() as batch:
result = batch.install("pkg")
# Verify installation succeeded
assert result is True
# First condition satisfied (numpy installed), so version 1.0 applied
install_calls = [cmd for cmd in call_sequence if "install" in cmd and "pkg" in cmd]
assert len(install_calls) > 0
assert "pkg==1.0" in install_calls[0]
assert "pkg==2.0" not in str(call_sequence) # Second policy not applied