From 02f17882615cd0601a62928c219aab709503d036 Mon Sep 17 00:00:00 2001 From: "Dr.Lt.Data" Date: Sun, 24 Nov 2024 23:33:53 +0900 Subject: [PATCH] feat: pip fixer for torch, opencv fixed: Preventing the browser from reopening automatically after a restart on Windows. --- glob/manager_core.py | 5 +- glob/manager_server.py | 5 ++ glob/manager_util.py | 150 +++++++++++++++++++++++++++++++++++++++++ prestartup_script.py | 30 ++------- pyproject.toml | 2 +- 5 files changed, 165 insertions(+), 27 deletions(-) diff --git a/glob/manager_core.py b/glob/manager_core.py index 562811c4..dec02771 100644 --- a/glob/manager_core.py +++ b/glob/manager_core.py @@ -23,7 +23,7 @@ sys.path.append(glob_path) import cm_global from manager_util import * -version = [2, 51, 9] +version = [2, 52] version_str = f"V{version[0]}.{version[1]}" + (f'.{version[2]}' if len(version) > 2 else '') @@ -408,6 +408,7 @@ def execute_install_script(url, repo_path, lazy_mode=False, instant_execution=Fa else: if os.path.exists(requirements_path): print("Install: pip packages") + pip_fixer = PIPFixer(get_installed_packages()) with open(requirements_path, "r") as requirements_file: for line in requirements_file: #handle comments @@ -430,6 +431,8 @@ def execute_install_script(url, repo_path, lazy_mode=False, instant_execution=Fa if package_name.strip() != "" and not package_name.startswith('#'): try_install_script(url, repo_path, install_cmd, instant_execution=instant_execution) + pip_fixer.fix_broken() + if os.path.exists(install_script_path): print(f"Install: install script") install_cmd = [sys.executable, "install.py"] diff --git a/glob/manager_server.py b/glob/manager_server.py index 0cc125c7..2da14785 100644 --- a/glob/manager_server.py +++ b/glob/manager_server.py @@ -1216,6 +1216,11 @@ def restart(self): exit(0) print(f"\nRestarting... [Legacy Mode]\n\n") + + sys_argv = sys.argv.copy() + if '--windows-standalone-build' in sys_argv: + sys_argv.remove('--windows-standalone-build') + if sys.platform.startswith('win32'): return os.execv(sys.executable, ['"' + sys.executable + '"', '"' + sys.argv[0] + '"'] + sys.argv[1:]) else: diff --git a/glob/manager_util.py b/glob/manager_util.py index c8a93d7b..7a7312e1 100644 --- a/glob/manager_util.py +++ b/glob/manager_util.py @@ -1,3 +1,6 @@ +import subprocess +import sys + # DON'T USE StrictVersion - cannot handle pre_release version # try: # from distutils.version import StrictVersion @@ -62,3 +65,150 @@ class StrictVersion: def __ne__(self, other): return not self == other + +pip_map = None + +def get_installed_packages(renew=False): + global pip_map + + if renew or pip_map is None: + try: + result = subprocess.check_output([sys.executable, '-m', 'pip', 'list'], universal_newlines=True) + + pip_map = {} + for line in result.split('\n'): + x = line.strip() + if x: + y = line.split() + if y[0] == 'Package' or y[0].startswith('-'): + continue + + pip_map[y[0]] = y[1] + except subprocess.CalledProcessError as e: + print(f"[ComfyUI-Manager] Failed to retrieve the information of installed pip packages.") + return set() + + return pip_map + + +def clear_pip_cache(): + global pip_map + pip_map = None + + +torch_torchvision_version_map = { + '2.5.1': '0.20.1', + '2.5.0': '0.20.0', + '2.4.1': '0.19.1', + '2.4.0': '0.19.0', + '2.3.1': '0.18.1', + '2.3.0': '0.18.0', + '2.2.2': '0.17.2', + '2.2.1': '0.17.1', + '2.2.0': '0.17.0', + '2.1.2': '0.16.2', + '2.1.1': '0.16.1', + '2.1.0': '0.16.0', + '2.0.1': '0.15.2', + '2.0.0': '0.15.1', +} + + +class PIPFixer: + def __init__(self, prev_pip_versions): + self.prev_pip_versions = { **prev_pip_versions } + + def torch_rollback(self): + spec = self.prev_pip_versions['torch'].split('+') + if len(spec) > 0: + platform = spec[1] + else: + cmd = [sys.executable, '-m', 'pip', 'install', '--force', 'torch', 'torchvision', 'torchaudio'] + subprocess.check_output(cmd, universal_newlines=True) + print(cmd) + return + + torch_ver = StrictVersion(spec[0]) + torch_ver = f"{torch_ver.major}.{torch_ver.minor}.{torch_ver.patch}" + torchvision_ver = torch_torchvision_version_map.get(torch_ver) + + if torchvision_ver is None: + cmd = [sys.executable, '-m', 'pip', 'install', '--pre', + 'torch', 'torchvision', 'torchaudio', + '--index-url', f"https://download.pytorch.org/whl/nightly/{platform}"] + print("[manager-core] restore PyTorch to nightly version") + else: + cmd = [sys.executable, '-m', 'pip', 'install', + f'torch=={torch_ver}', f'torchvision=={torchvision_ver}', f"torchaudio=={torch_ver}", + '--index-url', f"https://download.pytorch.org/whl/{platform}"] + print(f"[manager-core] restore PyTorch to {torch_ver}+{platform}") + + subprocess.check_output(cmd, universal_newlines=True) + + def fix_broken(self): + new_pip_versions = get_installed_packages(True) + + # remove `comfy` python package + try: + if 'comfy' in new_pip_versions: + cmd = [sys.executable, '-m', 'pip', 'uninstall', 'comfy'] + subprocess.check_output(cmd, universal_newlines=True) + + print(f"[manager-core] 'comfy' python package is uninstalled.\nWARN: The 'comfy' package is completely unrelated to ComfyUI and should never be installed as it causes conflicts with ComfyUI.") + except Exception as e: + print(f"[manager-core] Failed to uninstall `comfy` python package") + print(e) + + # fix torch - reinstall torch packages if version is changed + try: + if self.prev_pip_versions['torch'] != new_pip_versions['torch'] \ + or self.prev_pip_versions['torchvision'] != new_pip_versions['torchvision'] \ + or self.prev_pip_versions['torchaudio'] != new_pip_versions['torchaudio']: + self.torch_rollback() + except Exception as e: + print(f"[manager-core] Failed to restore PyTorch") + print(e) + + # fix opencv + try: + ocp = new_pip_versions.get('opencv-contrib-python') + ocph = new_pip_versions.get('opencv-contrib-python-headless') + op = new_pip_versions.get('opencv-python') + oph = new_pip_versions.get('opencv-python-headless') + + versions = [ocp, ocph, op, oph] + versions = [StrictVersion(x) for x in versions if x is not None] + versions.sort(reverse=True) + + if len(versions) > 0: + # upgrade to maximum version + targets = [] + cur = versions[0] + if ocp is not None and StrictVersion(ocp) != cur: + targets.append('opencv-contrib-python') + if ocph is not None and StrictVersion(ocph) != cur: + targets.append('opencv-contrib-python-headless') + if op is not None and StrictVersion(op) != cur: + targets.append('opencv-python') + if oph is not None and StrictVersion(oph) != cur: + targets.append('opencv-python-headless') + + if len(targets) > 0: + for x in targets: + cmd = [sys.executable, '-m', 'pip', 'install', f"{x}=={versions[0].version_string}"] + subprocess.check_output(cmd, universal_newlines=True) + + print(f"[manager-core] 'opencv' dependencies were fixed: {targets}") + except Exception as e: + print(f"[manager-core] Failed to restore opencv") + print(e) + + # fix numpy + try: + np = new_pip_versions.get('numpy') + if np is not None: + if StrictVersion(np) >= StrictVersion('2'): + subprocess.check_output([sys.executable, '-m', 'pip', 'install', f"numpy<2"], universal_newlines=True) + except Exception as e: + print(f"[manager-core] Failed to restore numpy") + print(e) diff --git a/prestartup_script.py b/prestartup_script.py index f4c6dc3f..8deb3a65 100644 --- a/prestartup_script.py +++ b/prestartup_script.py @@ -385,30 +385,7 @@ check_bypass_ssl() # Perform install processed_install = set() script_list_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "startup-scripts", "install-scripts.txt") -pip_map = None - - -def get_installed_packages(): - global pip_map - - if pip_map is None: - try: - result = subprocess.check_output([sys.executable, '-m', 'pip', 'list'], universal_newlines=True) - - pip_map = {} - for line in result.split('\n'): - x = line.strip() - if x: - y = line.split() - if y[0] == 'Package' or y[0].startswith('-'): - continue - - pip_map[y[0]] = y[1] - except subprocess.CalledProcessError as e: - print(f"[ComfyUI-Manager] Failed to retrieve the information of installed pip packages.") - return set() - - return pip_map +pip_fixer = PIPFixer(get_installed_packages()) def is_installed(name): @@ -620,8 +597,11 @@ if os.path.exists(script_list_path): print("\n[ComfyUI-Manager] Startup script completed.") print("#######################################################################\n") +pip_fixer.fix_broken() + del processed_install -del pip_map +del pip_fixer +clear_pip_cache() def check_windows_event_loop_policy(): diff --git a/pyproject.toml b/pyproject.toml index 611f07ba..077f3125 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "comfyui-manager" description = "ComfyUI-Manager provides features to install and manage custom nodes for ComfyUI, as well as various functionalities to assist with ComfyUI." -version = "2.51.9" +version = "2.52" license = { file = "LICENSE.txt" } dependencies = ["GitPython", "PyGithub", "matrix-client==0.4.0", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions"]