refactor: remove package-level caching to support dynamic installation

Remove package-level caching in cnr_utils and node_package modules to enable
proper dynamic custom node installation and version switching without ComfyUI
server restarts.

Key Changes:
- Remove @lru_cache decorators from version-sensitive functions
- Remove cached_property from NodePackage for dynamic state updates
- Add comprehensive test suite with parallel execution support
- Implement version switching tests (CNR ↔ Nightly)
- Add case sensitivity integration tests
- Improve error handling and logging

API Priority Rules (manager_core.py:1801):
- Enabled-Priority: Show only enabled version when both exist
- CNR-Priority: Show only CNR when both CNR and Nightly are disabled
- Prevents duplicate package entries in /v2/customnode/installed API
- Cross-match using cnr_id and aux_id for CNR ↔ Nightly detection

Test Infrastructure:
- 8 test files with 59 comprehensive test cases
- Parallel test execution across 5 isolated environments
- Automated test scripts with environment setup
- Configurable timeout (60 minutes default)
- Support for both master and dr-support-pip-cm branches

Bug Fixes:
- Fix COMFYUI_CUSTOM_NODES_PATH environment variable export
- Resolve test fixture regression with module-level variables
- Fix import timing issues in test configuration
- Register pytest integration marker to eliminate warnings
- Fix POSIX compliance in shell scripts (((var++)) → $((var + 1)))

Documentation:
- CNR_VERSION_MANAGEMENT_DESIGN.md v1.0 → v1.1 with API priority rules
- Add test guides and execution documentation (TESTING_PROMPT.md)
- Add security-enhanced installation guide
- Create CLI migration guides and references
- Document package version management

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Dr.Lt.Data
2025-11-07 10:04:21 +09:00
parent d3906e3cbc
commit 43647249cf
62 changed files with 17790 additions and 10789 deletions

View File

@@ -14,6 +14,7 @@ class InstalledNodePackage:
fullpath: str
disabled: bool
version: str
repo_url: str = None # Git repository URL for nightly packages
@property
def is_unknown(self) -> bool:
@@ -46,6 +47,8 @@ class InstalledNodePackage:
@staticmethod
def from_fullpath(fullpath: str, resolve_from_path) -> InstalledNodePackage:
from . import git_utils
parent_folder_name = os.path.basename(os.path.dirname(fullpath))
module_name = os.path.basename(fullpath)
@@ -54,6 +57,10 @@ class InstalledNodePackage:
disabled = True
elif parent_folder_name == ".disabled":
# Nodes under custom_nodes/.disabled/* are disabled
# Parse directory name format: packagename@version
# Examples:
# comfyui_sigmoidoffsetscheduler@nightly → id: comfyui_sigmoidoffsetscheduler, version: nightly
# comfyui_sigmoidoffsetscheduler@1_0_2 → id: comfyui_sigmoidoffsetscheduler, version: 1.0.2
node_id = module_name
disabled = True
else:
@@ -61,12 +68,35 @@ class InstalledNodePackage:
disabled = False
info = resolve_from_path(fullpath)
repo_url = None
version_from_dirname = None
# For disabled packages, try to extract version from directory name
if disabled and parent_folder_name == ".disabled" and '@' in module_name:
parts = module_name.split('@')
if len(parts) == 2:
node_id = parts[0] # Use the normalized name from directory
version_from_dirname = parts[1].replace('_', '.') # Convert 1_0_2 → 1.0.2
if info is None:
version = 'unknown'
version = version_from_dirname if version_from_dirname else 'unknown'
else:
node_id = info['id'] # robust module guessing
version = info['ver']
# Prefer version from directory name for disabled packages (preserves 'nightly' literal)
# Otherwise use version from package inspection (commit hash for git repos)
if version_from_dirname:
version = version_from_dirname
else:
version = info['ver']
# Get repository URL for both nightly and CNR packages
if version == 'nightly':
# For nightly packages, get repo URL from git
repo_url = git_utils.git_url(fullpath)
elif 'url' in info and info['url']:
# For CNR packages, get repo URL from pyproject.toml
repo_url = info['url']
return InstalledNodePackage(
id=node_id, fullpath=fullpath, disabled=disabled, version=version
id=node_id, fullpath=fullpath, disabled=disabled, version=version, repo_url=repo_url
)