diff --git a/README.md b/README.md index 1ba9b2a42..0ec509439 100644 --- a/README.md +++ b/README.md @@ -696,86 +696,67 @@ You can pass additional extra model path configurations with one or more copies ### Command Line Arguments ``` -usage: comfyui.exe [-h] [-c CONFIG_FILE] - [--write-out-config-file CONFIG_OUTPUT_PATH] [-w CWD] - [--base-paths BASE_PATHS [BASE_PATHS ...]] [-H [IP]] - [--port PORT] [--enable-cors-header [ORIGIN]] - [--max-upload-size MAX_UPLOAD_SIZE] - [--base-directory BASE_DIRECTORY] - [--extra-model-paths-config PATH [PATH ...]] - [--output-directory OUTPUT_DIRECTORY] - [--temp-directory TEMP_DIRECTORY] - [--input-directory INPUT_DIRECTORY] [--auto-launch] - [--disable-auto-launch] [--cuda-device DEVICE_ID] - [--cuda-malloc | --disable-cuda-malloc] - [--force-fp32 | --force-fp16 | --force-bf16] - [--fp32-unet | --fp64-unet | --bf16-unet | --fp16-unet | --fp8_e4m3fn-unet | --fp8_e5m2-unet | --fp8_e8m0fnu-unet] - [--fp16-vae | --fp32-vae | --bf16-vae] [--cpu-vae] - [--fp8_e4m3fn-text-enc | --fp8_e5m2-text-enc | --fp16-text-enc | --fp32-text-enc | --bf16-text-enc] - [--directml [DIRECTML_DEVICE]] - [--oneapi-device-selector SELECTOR_STRING] - [--disable-ipex-optimize] [--supports-fp8-compute] - [--preview-method [none,auto,latent2rgb,taesd]] - [--preview-size PREVIEW_SIZE] - [--cache-classic | --cache-lru CACHE_LRU | --cache-none] - [--use-split-cross-attention | --use-quad-cross-attention | --use-pytorch-cross-attention | --use-sage-attention | --use-flash-attention] - [--disable-xformers] - [--force-upcast-attention | --dont-upcast-attention] - [--gpu-only | --highvram | --normalvram | --lowvram | --novram | --cpu] - [--reserve-vram RESERVE_VRAM] [--async-offload] - [--default-hashing-function {md5,sha1,sha256,sha512}] - [--disable-smart-memory] [--deterministic] - [--fast [FAST ...]] [--mmap-torch-files] [--disable-mmap] - [--dont-print-server] [--quick-test-for-ci] - [--windows-standalone-build] [--disable-metadata] - [--disable-all-custom-nodes] - [--whitelist-custom-nodes WHITELIST_CUSTOM_NODES [WHITELIST_CUSTOM_NODES ...]] - [--disable-api-nodes] [--multi-user] [--create-directories] - [--log-stdout] - [--plausible-analytics-base-url PLAUSIBLE_ANALYTICS_BASE_URL] - [--plausible-analytics-domain PLAUSIBLE_ANALYTICS_DOMAIN] - [--analytics-use-identity-provider] - [--distributed-queue-connection-uri DISTRIBUTED_QUEUE_CONNECTION_URI] - [--distributed-queue-worker] [--distributed-queue-frontend] - [--distributed-queue-name DISTRIBUTED_QUEUE_NAME] - [--external-address EXTERNAL_ADDRESS] - [--logging-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}] - [--disable-known-models] [--max-queue-size MAX_QUEUE_SIZE] - [--otel-service-name OTEL_SERVICE_NAME] - [--otel-service-version OTEL_SERVICE_VERSION] - [--otel-exporter-otlp-endpoint OTEL_EXPORTER_OTLP_ENDPOINT] - [--force-channels-last] [--force-hf-local-dir-mode] - [--front-end-version FRONT_END_VERSION] - [--panic-when PANIC_WHEN] [--front-end-root FRONT_END_ROOT] - [--executor-factory EXECUTOR_FACTORY] - [--openai-api-key OPENAI_API_KEY] - [--ideogram-api-key IDEOGRAM_API_KEY] - [--anthropic-api-key ANTHROPIC_API_KEY] - [--user-directory USER_DIRECTORY] - [--enable-compress-response-body] - [--comfy-api-base COMFY_API_BASE] - [--database-url DATABASE_URL] - [--workflows WORKFLOWS [WORKFLOWS ...]] - [--blip-model-url BLIP_MODEL_URL] - [--blip-model-vqa-url BLIP_MODEL_VQA_URL] - [--sam-model-vith-url SAM_MODEL_VITH_URL] - [--sam-model-vitl-url SAM_MODEL_VITL_URL] - [--sam-model-vitb-url SAM_MODEL_VITB_URL] - [--history-display-limit HISTORY_DISPLAY_LIMIT] - [--ffmpeg-bin-path FFMPEG_BIN_PATH] - [--ffmpeg-extra-codecs FFMPEG_EXTRA_CODECS] - [--wildcards-path WILDCARDS_PATH] - [--wildcard-api WILDCARD_API] - [--photoprism-host PHOTOPRISM_HOST] - [--immich-host IMMICH_HOST] - [--ideogram-session-cookie IDEOGRAM_SESSION_COOKIE] - [--use-symlinks] [--ort-providers ORT_PROVIDERS] - [--vfi-ops-backend VFI_OPS_BACKEND] - [--dependency-version DEPENDENCY_VERSION] [--mmdet-skip] - [--sam-editor-cpu] [--sam-editor-model SAM_EDITOR_MODEL] - [--custom-wildcards CUSTOM_WILDCARDS] - [--disable-gpu-opencv] - +usage: comfyui [-h] [-c CONFIG_FILE] + [--write-out-config-file CONFIG_OUTPUT_PATH] [-w CWD] + [--base-paths BASE_PATHS [BASE_PATHS ...]] [-H [IP]] + [--port PORT] [--enable-cors-header [ORIGIN]] + [--max-upload-size MAX_UPLOAD_SIZE] + [--base-directory BASE_DIRECTORY] + [--extra-model-paths-config PATH [PATH ...]] + [--output-directory OUTPUT_DIRECTORY] + [--temp-directory TEMP_DIRECTORY] + [--input-directory INPUT_DIRECTORY] [--auto-launch] + [--disable-auto-launch] [--cuda-device DEVICE_ID] + [--default-device DEFAULT_DEVICE_ID] + [--cuda-malloc | --disable-cuda-malloc] + [--force-fp32 | --force-fp16 | --force-bf16] + [--fp32-unet | --fp64-unet | --bf16-unet | --fp16-unet | --fp8_e4m3fn-unet | --fp8_e5m2-unet | --fp8_e8m0fnu-unet] + [--fp16-vae | --fp32-vae | --bf16-vae] [--cpu-vae] + [--fp8_e4m3fn-text-enc | --fp8_e5m2-text-enc | --fp16-text-enc | --fp32-text-enc | --bf16-text-enc] + [--directml [DIRECTML_DEVICE]] + [--oneapi-device-selector SELECTOR_STRING] + [--disable-ipex-optimize] [--supports-fp8-compute] + [--preview-method [none,auto,latent2rgb,taesd]] + [--preview-size PREVIEW_SIZE] + [--cache-classic | --cache-lru CACHE_LRU | --cache-none] + [--use-split-cross-attention | --use-quad-cross-attention | --use-pytorch-cross-attention | --use-sage-attention | --use-flash-attention] + [--disable-xformers] + [--force-upcast-attention | --dont-upcast-attention] + [--gpu-only | --highvram | --normalvram | --lowvram | --novram | --cpu] + [--reserve-vram RESERVE_VRAM] [--async-offload] + [--force-non-blocking] + [--default-hashing-function {md5,sha1,sha256,sha512}] + [--disable-smart-memory] [--deterministic] [--fast [FAST ...]] + [--mmap-torch-files] [--disable-mmap] [--dont-print-server] + [--quick-test-for-ci] [--windows-standalone-build] + [--disable-metadata] [--disable-all-custom-nodes] + [--whitelist-custom-nodes WHITELIST_CUSTOM_NODES [WHITELIST_CUSTOM_NODES ...]] + [--blacklist-custom-nodes BLACKLIST_CUSTOM_NODES [BLACKLIST_CUSTOM_NODES ...]] + [--disable-api-nodes] [--multi-user] [--create-directories] + [--log-stdout] + [--plausible-analytics-base-url PLAUSIBLE_ANALYTICS_BASE_URL] + [--plausible-analytics-domain PLAUSIBLE_ANALYTICS_DOMAIN] + [--analytics-use-identity-provider] + [--distributed-queue-connection-uri DISTRIBUTED_QUEUE_CONNECTION_URI] + [--distributed-queue-worker] [--distributed-queue-frontend] + [--distributed-queue-name DISTRIBUTED_QUEUE_NAME] + [--external-address EXTERNAL_ADDRESS] + [--logging-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}] + [--disable-known-models] [--max-queue-size MAX_QUEUE_SIZE] + [--otel-service-name OTEL_SERVICE_NAME] + [--otel-service-version OTEL_SERVICE_VERSION] + [--otel-exporter-otlp-endpoint OTEL_EXPORTER_OTLP_ENDPOINT] + [--force-channels-last] [--force-hf-local-dir-mode] + [--front-end-version FRONT_END_VERSION] + [--panic-when PANIC_WHEN] [--front-end-root FRONT_END_ROOT] + [--executor-factory EXECUTOR_FACTORY] + [--openai-api-key OPENAI_API_KEY] + [--ideogram-api-key IDEOGRAM_API_KEY] + [--anthropic-api-key ANTHROPIC_API_KEY] + [--user-directory USER_DIRECTORY] + [--enable-compress-response-body] + [--comfy-api-base COMFY_API_BASE] [--database-url DATABASE_URL] + [--workflows WORKFLOWS [WORKFLOWS ...]] options: -h, --help show this help message and exit -c CONFIG_FILE, --config CONFIG_FILE @@ -829,7 +810,11 @@ options: COMFYUI_DISABLE_AUTO_LAUNCH] --cuda-device DEVICE_ID Set the id of the cuda device this instance will use. - [env var: COMFYUI_CUDA_DEVICE] + All other devices will not be visible. [env var: + COMFYUI_CUDA_DEVICE] + --default-device DEFAULT_DEVICE_ID + Set the id of the default device, all other devices + will stay visible. [env var: COMFYUI_DEFAULT_DEVICE] --cuda-malloc Enable cudaMallocAsync (enabled by default for torch 2.0 and up). [env var: COMFYUI_CUDA_MALLOC] --disable-cuda-malloc @@ -941,13 +926,17 @@ options: COMFYUI_RESERVE_VRAM] --async-offload Use async weight offloading. [env var: COMFYUI_ASYNC_OFFLOAD] + --force-non-blocking Force ComfyUI to use non-blocking operations for all + applicable tensors. This may improve performance on + some non-Nvidia systems but can cause issues with some + workflows. [env var: COMFYUI_FORCE_NON_BLOCKING] --default-hashing-function {md5,sha1,sha256,sha512} Allows you to choose the hash function to use for duplicate filename / contents comparison. Default is sha256. [env var: COMFYUI_DEFAULT_HASHING_FUNCTION] --disable-smart-memory - Force ComfyUI to agressively offload to regular ram - instead of keeping models in vram when it can. [env + Force ComfyUI to aggressively offload to regular ram + instead of keeping models in VRAM when it can. [env var: COMFYUI_DISABLE_SMART_MEMORY] --deterministic Make pytorch use slower deterministic algorithms when it can. Note that this might not make images @@ -957,7 +946,8 @@ options: deteriorating optimizations. Pass a list specific optimizations if you only want to enable specific ones. Current valid optimizations: fp16_accumulation - fp8_matrix_mult cublas_ops [env var: COMFYUI_FAST] + fp8_matrix_mult cublas_ops autotune [env var: + COMFYUI_FAST] --mmap-torch-files Use mmap when loading ckpt/pt files. [env var: COMFYUI_MMAP_TORCH_FILES] --disable-mmap Don't use mmap when loading safetensors. [env var: @@ -980,6 +970,10 @@ options: Specify custom node folders to load even when --disable-all-custom-nodes is enabled. [env var: COMFYUI_WHITELIST_CUSTOM_NODES] + --blacklist-custom-nodes BLACKLIST_CUSTOM_NODES [BLACKLIST_CUSTOM_NODES ...] + Specify custom node folders to never load. Accepts + shell-style globs. [env var: + COMFYUI_BLACKLIST_CUSTOM_NODES] --disable-api-nodes Disable loading all api nodes. [env var: COMFYUI_DISABLE_API_NODES] --multi-user Enables per-user storage. [env var: @@ -1119,10 +1113,10 @@ options: standard in. [env var: COMFYUI_WORKFLOWS] Args that start with '--' can also be set in a config file (config.yaml or -config.json or specified via -c). Config file syntax allows: key=value, -flag=true, stuff=[a,b,c] (for details, see syntax at https://goo.gl/R74nmi). -In general, command-line values override environment variables which override -config file values which override defaults. +config.json or config.cfg or config.ini or specified via -c). Config file +syntax allows: key=value, flag=true, stuff=[a,b,c] (for details, see syntax at +https://goo.gl/R74nmi). In general, command-line values override environment +variables which override config file values which override defaults. ``` diff --git a/comfy/cli_args.py b/comfy/cli_args.py index b06bfd7e4..6fd167aa0 100644 --- a/comfy/cli_args.py +++ b/comfy/cli_args.py @@ -148,6 +148,7 @@ def _create_parser() -> EnhancedConfigArgParser: parser.add_argument("--disable-metadata", action="store_true", help="Disable saving prompt metadata in files.") parser.add_argument("--disable-all-custom-nodes", action="store_true", help="Disable loading all custom nodes.") parser.add_argument("--whitelist-custom-nodes", type=str, nargs='+', default=[], help="Specify custom node folders to load even when --disable-all-custom-nodes is enabled.") + parser.add_argument("--blacklist-custom-nodes", type=str, nargs='+', default=[], help="Specify custom node folders to never load. Accepts shell-style globs.") parser.add_argument("--disable-api-nodes", action="store_true", help="Disable loading all api nodes.") parser.add_argument("--multi-user", action="store_true", help="Enables per-user storage.") diff --git a/comfy/cli_args_types.py b/comfy/cli_args_types.py index 19f6fa27e..8f32defa6 100644 --- a/comfy/cli_args_types.py +++ b/comfy/cli_args_types.py @@ -166,6 +166,7 @@ class Configuration(dict): front_end_root (Optional[str]): The local filesystem path to the directory where the frontend is located. Overrides --front-end-version. comfy_api_base (str): Set the base URL for the ComfyUI API. (default: https://api.comfy.org) database_url (str): Specify the database URL, e.g. for an in-memory database you can use 'sqlite:///:memory:'. + blacklist_custom_nodes (list[str]): Specify custom node folders to never load. Accepts shell-style globs. whitelist_custom_nodes (list[str]): Specify custom node folders to load even when --disable-all-custom-nodes is enabled. default_device (Optional[int]): Set the id of the default device, all other devices will stay visible. """ @@ -234,6 +235,7 @@ class Configuration(dict): self.windows_standalone_build: bool = False self.disable_metadata: bool = False self.disable_all_custom_nodes: bool = False + self.blacklist_custom_nodes: list[str] = [] self.whitelist_custom_nodes: list[str] = [] self.multi_user: bool = False self.plausible_analytics_base_url: Optional[str] = None diff --git a/comfy/nodes/vanilla_node_importing.py b/comfy/nodes/vanilla_node_importing.py index 4eb8810ae..971455fa7 100644 --- a/comfy/nodes/vanilla_node_importing.py +++ b/comfy/nodes/vanilla_node_importing.py @@ -5,6 +5,7 @@ import importlib.util import logging import os import sys +import fnmatch import time import types from contextlib import contextmanager @@ -222,6 +223,9 @@ def _vanilla_load_custom_nodes_2(node_paths: Iterable[str]) -> ExportedNodes: if args.disable_all_custom_nodes and possible_module not in args.whitelist_custom_nodes: logger.info(f"Skipping {possible_module} due to disable_all_custom_nodes and whitelist_custom_nodes") continue + if any(fnmatch.fnmatch(possible_module, pattern) for pattern in args.blacklist_custom_nodes): + logger.info(f"Skipping {possible_module} due to blacklist_custom_nodes") + continue time_before = time.perf_counter() possible_exported_nodes = _vanilla_load_custom_nodes_1(module_path, ignore=base_node_names) # comfyui-manager mitigation diff --git a/tests/issues/custom_nodes/issue_46/__init__.py b/tests/issues/custom_nodes/issue_46/__init__.py new file mode 100644 index 000000000..1b50eebdf --- /dev/null +++ b/tests/issues/custom_nodes/issue_46/__init__.py @@ -0,0 +1,18 @@ +from comfy.nodes.package_typing import CustomNode, InputTypes, FunctionReturnsUIVariables + + +class ShouldNotExist(CustomNode): + @classmethod + def INPUT_TYPES(cls) -> InputTypes: + return {"required": {}} + + FUNCTION = "execute" + OUTPUT_NODE = True + + def execute(self) -> tuple[...,]: + return None, + + +NODE_CLASS_MAPPINGS = { + "ShouldNotExist": ShouldNotExist +} diff --git a/tests/issues/__test_25_respect_cwd_param.py b/tests/issues/test_25_respect_cwd_param.py similarity index 100% rename from tests/issues/__test_25_respect_cwd_param.py rename to tests/issues/test_25_respect_cwd_param.py diff --git a/tests/issues/__test_29_fix_str_in_model.py b/tests/issues/test_29_fix_str_in_model.py similarity index 100% rename from tests/issues/__test_29_fix_str_in_model.py rename to tests/issues/test_29_fix_str_in_model.py diff --git a/tests/issues/__test_30_comfy_workspace_conflicts.py b/tests/issues/test_30_comfy_workspace_conflicts.py similarity index 100% rename from tests/issues/__test_30_comfy_workspace_conflicts.py rename to tests/issues/test_30_comfy_workspace_conflicts.py diff --git a/tests/issues/test_46_blacklist_nodes.py b/tests/issues/test_46_blacklist_nodes.py new file mode 100644 index 000000000..57d10902a --- /dev/null +++ b/tests/issues/test_46_blacklist_nodes.py @@ -0,0 +1,48 @@ +import pytest +from importlib.resources import files + +from comfy.api.components.schema.prompt import Prompt +from comfy.cli_args_types import Configuration +from comfy.client.embedded_comfy_client import Comfy + +_TEST_WORKFLOW_1 = { + "0": { + "inputs": {}, + "class_type": "ShouldNotExist", + "_meta": { + "title": "" + } + }, + "1": { + "inputs": {}, + "class_type": "TestPath", + "_meta": { + "title": "" + } + } +} + +_TEST_WORKFLOW_2 = { + "1": { + "inputs": {}, + "class_type": "TestPath", + "_meta": { + "title": "" + } + } +} + + +@pytest.mark.asyncio +async def test_blacklist_node(): + config = Configuration(blacklist_custom_nodes=['issue_46']) + # for finding the custom nodes + config.base_paths = [str(files(__package__))] + + async with Comfy(config) as client: + from comfy.cmd.execution import validate_prompt + res = await validate_prompt("1", prompt=_TEST_WORKFLOW_1, partial_execution_list=[]) + assert "ShouldNotExist" in res.error["message"] + assert res.error["type"] == "invalid_prompt" + res = await validate_prompt("2", prompt=_TEST_WORKFLOW_2, partial_execution_list=[]) + assert "TestPath" not in res.error, "successfully loaded issue_25 nodes"