From 1bc96a7a1b9bdf3aa97a595b9540c807f770b025 Mon Sep 17 00:00:00 2001 From: doctorpangloss <@hiddenswitch.com> Date: Thu, 29 Aug 2024 18:02:36 -0700 Subject: [PATCH] Fix #20 base path can now be set before folder paths are initialized, although all of this really has to be reworked --- comfy/cmd/folder_paths.py | 40 ++++++++++-------------- comfy/cmd/folder_paths_pre.py | 31 ++++++++++++++++++ comfy/cmd/main.py | 15 +++++++-- comfy/component_model/module_property.py | 22 +++++++++++++ main.py | 12 +++++-- 5 files changed, 92 insertions(+), 28 deletions(-) create mode 100644 comfy/cmd/folder_paths_pre.py create mode 100644 comfy/component_model/module_property.py diff --git a/comfy/cmd/folder_paths.py b/comfy/cmd/folder_paths.py index d1ef611f0..5435a68f4 100644 --- a/comfy/cmd/folder_paths.py +++ b/comfy/cmd/folder_paths.py @@ -2,31 +2,25 @@ from __future__ import annotations import logging import os -import sys import time -from typing import Optional, List +from typing import Optional, List, Final -from ..cli_args import args +from .folder_paths_pre import get_base_path from ..component_model.files import get_package_as_path from ..component_model.folder_path_types import FolderPathsTuple, FolderNames, SaveImagePathResponse from ..component_model.folder_path_types import supported_pt_extensions as _supported_pt_extensions +from ..component_model.module_property import module_property -supported_pt_extensions = _supported_pt_extensions +supported_pt_extensions: Final[frozenset[str]] = _supported_pt_extensions -# todo: this should be initialized elsewhere -if 'main.py' in sys.argv: - base_path = os.path.realpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../..")) # pylint: disable=used-before-assignment -elif args.cwd is not None: - if not os.path.exists(args.cwd): - try: - os.makedirs(args.cwd, exist_ok=True) - except: - logging.error("Failed to create custom working directory") - # wrap the path to prevent slashedness from glitching out common path checks - base_path = os.path.realpath(args.cwd) -else: - base_path = os.getcwd() -models_dir = os.path.join(base_path, "models") + +# todo: this needs to be wrapped in a context and configurable +@module_property +def _base_path(): + return get_base_path() + + +models_dir = os.path.join(get_base_path(), "models") folder_names_and_paths = FolderNames(models_dir) folder_names_and_paths["checkpoints"] = FolderPathsTuple("checkpoints", [os.path.join(models_dir, "checkpoints")], set(supported_pt_extensions)) folder_names_and_paths["configs"] = FolderPathsTuple("configs", [os.path.join(models_dir, "configs"), get_package_as_path("comfy.configs")], {".yaml"}) @@ -42,17 +36,17 @@ folder_names_and_paths["vae_approx"] = FolderPathsTuple("vae_approx", [os.path.j folder_names_and_paths["controlnet"] = FolderPathsTuple("controlnet", [os.path.join(models_dir, "controlnet"), os.path.join(models_dir, "t2i_adapter")], set(supported_pt_extensions)) folder_names_and_paths["gligen"] = FolderPathsTuple("gligen", [os.path.join(models_dir, "gligen")], set(supported_pt_extensions)) folder_names_and_paths["upscale_models"] = FolderPathsTuple("upscale_models", [os.path.join(models_dir, "upscale_models")], set(supported_pt_extensions)) -folder_names_and_paths["custom_nodes"] = FolderPathsTuple("custom_nodes", [os.path.join(base_path, "custom_nodes")], set()) +folder_names_and_paths["custom_nodes"] = FolderPathsTuple("custom_nodes", [os.path.join(get_base_path(), "custom_nodes")], set()) folder_names_and_paths["hypernetworks"] = FolderPathsTuple("hypernetworks", [os.path.join(models_dir, "hypernetworks")], set(supported_pt_extensions)) folder_names_and_paths["photomaker"] = FolderPathsTuple("photomaker", [os.path.join(models_dir, "photomaker")], set(supported_pt_extensions)) folder_names_and_paths["classifiers"] = FolderPathsTuple("classifiers", [os.path.join(models_dir, "classifiers")], {""}) folder_names_and_paths["huggingface"] = FolderPathsTuple("huggingface", [os.path.join(models_dir, "huggingface")], {""}) folder_names_and_paths["huggingface_cache"] = FolderPathsTuple("huggingface_cache", [os.path.join(models_dir, "huggingface_cache")], {""}) -output_directory = os.path.join(base_path, "output") -temp_directory = os.path.join(base_path, "temp") -input_directory = os.path.join(base_path, "input") -user_directory = os.path.join(base_path, "user") +output_directory = os.path.join(get_base_path(), "output") +temp_directory = os.path.join(get_base_path(), "temp") +input_directory = os.path.join(get_base_path(), "input") +user_directory = os.path.join(get_base_path(), "user") _filename_list_cache = {} diff --git a/comfy/cmd/folder_paths_pre.py b/comfy/cmd/folder_paths_pre.py new file mode 100644 index 000000000..dbf0d5885 --- /dev/null +++ b/comfy/cmd/folder_paths_pre.py @@ -0,0 +1,31 @@ +import logging +import os + +from ..cli_args import args + +_base_path = None + + +# todo: this should be initialized elsewhere in a context +def get_base_path() -> str: + global _base_path + if _base_path is None: + if args.cwd is not None: + if not os.path.exists(args.cwd): + try: + os.makedirs(args.cwd, exist_ok=True) + except: + logging.error("Failed to create custom working directory") + # wrap the path to prevent slashedness from glitching out common path checks + _base_path = os.path.realpath(args.cwd) + else: + _base_path = os.getcwd() + return _base_path + + +def set_base_path(value: str): + global _base_path + _base_path = value + + +__all__ = ["get_base_path", "set_base_path"] diff --git a/comfy/cmd/main.py b/comfy/cmd/main.py index 0014a4611..6b53995cb 100644 --- a/comfy/cmd/main.py +++ b/comfy/cmd/main.py @@ -6,6 +6,8 @@ import os import shutil import threading import time +from pathlib import Path +from typing import Optional from .extra_model_paths import load_extra_path_config # main_pre must be the earliest import since it suppresses some spurious warnings @@ -107,7 +109,16 @@ def cuda_malloc_warning(): "\nWARNING: this card most likely does not support cuda-malloc, if you get \"CUDA error\" please run ComfyUI with: --disable-cuda-malloc\n") -async def main(): +async def main(from_script_dir: Optional[Path] = None): + """ + Runs ComfyUI's frontend and backend like upstream. + :param from_script_dir: when set to a path, assumes that you are running ComfyUI's legacy main.py entrypoint at the root of the git repository located at the path + """ + if not from_script_dir: + os_getcwd = os.getcwd() + else: + os_getcwd = str(from_script_dir) + if args.temp_directory: temp_dir = os.path.join(os.path.abspath(args.temp_directory), "temp") logging.debug(f"Setting temp directory to: {temp_dir}") @@ -116,7 +127,7 @@ async def main(): # configure extra model paths earlier try: - extra_model_paths_config_path = os.path.join(os.getcwd(), "extra_model_paths.yaml") + extra_model_paths_config_path = os.path.join(os_getcwd, "extra_model_paths.yaml") if os.path.isfile(extra_model_paths_config_path): load_extra_path_config(extra_model_paths_config_path) except NameError: diff --git a/comfy/component_model/module_property.py b/comfy/component_model/module_property.py new file mode 100644 index 000000000..b93f2045a --- /dev/null +++ b/comfy/component_model/module_property.py @@ -0,0 +1,22 @@ +import sys + + +def module_property(func): + """Decorator to turn module functions into properties. + Function names must be prefixed with an underscore.""" + module = sys.modules[func.__module__] + + def base_getattr(name): + raise AttributeError( + f"module '{module.__name__}' has no attribute '{name}'") + + old_getattr = getattr(module, '__getattr__', base_getattr) + + def new_getattr(name): + if f'_{name}' == func.__name__: + return func() + else: + return old_getattr(name) + + module.__getattr__ = new_getattr + return func diff --git a/main.py b/main.py index 67a5e8d54..c1ef41468 100644 --- a/main.py +++ b/main.py @@ -1,8 +1,14 @@ import asyncio import warnings - -from comfy.cmd.main import main +from pathlib import Path if __name__ == "__main__": + from comfy.cmd.folder_paths_pre import set_base_path + warnings.warn("main.py is deprecated. Start comfyui by installing the package through the instructions in the README, not by cloning the repository.", DeprecationWarning) - asyncio.run(main()) + this_file_parent_dir = Path(__file__).parent + set_base_path(str(this_file_parent_dir)) + + from comfy.cmd.main import main + + asyncio.run(main(from_script_dir=this_file_parent_dir))