Guest User

custom_nodes_checker.py

a guest
Aug 22nd, 2024
672
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.88 KB | Source Code | 0 0
  1. import json
  2. import os
  3. import re
  4. import sys
  5.  
  6. IGNORED_NODES = {"Note", "PrimitiveNode", "Reroute"}
  7.  
  8.  
  9. def get_nodes_from_python_file(filepath):
  10.     # Extract node names from a `nodes*.py` file based on its NODE_CLASS_MAPPINGS dictionary.
  11.     if not os.path.exists(filepath):
  12.         print(f"Error: '{filepath}' not found.")
  13.         sys.exit(1)
  14.     if os.path.isdir(filepath):
  15.         print(f"Error: '{filepath}' is a directory, expected a Python file.")
  16.         sys.exit(1)
  17.  
  18.     nodes = set()
  19.     node_class_mappings_found = False
  20.     node_pattern = re.compile(r'"([^"]+)"')
  21.  
  22.     with open(filepath, "r") as file:
  23.         for line in file:
  24.             line = line.strip()
  25.             if line.startswith("NODE_CLASS_MAPPINGS"):
  26.                 node_class_mappings_found = True
  27.                 continue
  28.             if node_class_mappings_found:
  29.                 if line.startswith("}"):
  30.                     break
  31.                 # Find all matches between quotes and add to the set
  32.                 matches = node_pattern.findall(line)
  33.                 nodes.update(matches)
  34.  
  35.     return nodes
  36.  
  37.  
  38. def get_built_in_nodes(comfyui_path):
  39.     # Collect all built-in nodes by parsing `nodes.py` file and any` nodes_*.py` files
  40.     # in `comfy_extras`.
  41.  
  42.     main_nodes_py_path = os.path.join(comfyui_path, "nodes.py")
  43.     built_in_nodes = get_nodes_from_python_file(main_nodes_py_path)
  44.  
  45.     comfy_extras_dir = os.path.join(comfyui_path, "comfy_extras")
  46.     if os.path.exists(comfy_extras_dir) and os.path.isdir(comfy_extras_dir):
  47.         for filename in os.listdir(comfy_extras_dir):
  48.             if filename.startswith("nodes_") and filename.endswith(".py"):
  49.                 extras_file_path = os.path.join(comfy_extras_dir, filename)
  50.                 extras_nodes = get_nodes_from_python_file(extras_file_path)
  51.                 built_in_nodes.update(extras_nodes)
  52.  
  53.     return built_in_nodes
  54.  
  55.  
  56. def get_nodes_from_workflow_json_file(filepath):
  57.     # Extract node types from a workflow JSON file.
  58.  
  59.     types = set()
  60.  
  61.     with open(filepath, "r") as file:
  62.         data = json.load(file)
  63.         nodes = data.get("nodes", [])
  64.         for node in nodes:
  65.             node_type = node.get("type")
  66.             if node_type:
  67.                 types.add(node_type.strip())
  68.  
  69.     return list(types)
  70.  
  71.  
  72. def compare_nodes(built_in_nodes, workflow_nodes):
  73.     # Compare the built-in nodes with the nodes used in the workflow.
  74.  
  75.     workflow_nodes = [node for node in workflow_nodes if node not in IGNORED_NODES]
  76.     missing_nodes = sorted(
  77.         [
  78.             workflow_node
  79.             for workflow_node in workflow_nodes
  80.             if workflow_node not in built_in_nodes
  81.         ]
  82.     )
  83.     return missing_nodes
  84.  
  85.  
  86. def load_extension_node_map(extension_node_map_path):
  87.     # Load ComfyUI Manager `extension-node-map.json` file if it exists.
  88.  
  89.     if not os.path.exists(extension_node_map_path):
  90.         print(
  91.             "ComfyUI Manager is not installed. Install it to get additional custom node information."
  92.         )
  93.         return None
  94.  
  95.     with open(extension_node_map_path, "r") as file:
  96.         extension_node_map = json.load(file)
  97.  
  98.     return extension_node_map
  99.  
  100.  
  101. def find_node_in_extension_map(node_name, extension_node_map):
  102.     # Find the URL corresponding to a node name in the `extension-node-map.json`.
  103.  
  104.     for url, (nodes, _) in extension_node_map.items():
  105.         if node_name in nodes:
  106.             return url
  107.     return None
  108.  
  109.  
  110. def process_workflow_json(file_path, built_in_nodes, extension_node_map):
  111.     # Process a workflow JSON file, comparing its nodes with the built-in nodes and
  112.     # optionally checking the `extension-node-map.json`.
  113.  
  114.     workflow_nodes = get_nodes_from_workflow_json_file(file_path)
  115.     missing_nodes = compare_nodes(built_in_nodes, workflow_nodes)
  116.     json_filename = os.path.basename(file_path)  # Get the filename from the path
  117.     print(f"\n{json_filename}")
  118.     if missing_nodes:
  119.         for missing_node in missing_nodes:
  120.             if extension_node_map:
  121.                 extension_url = find_node_in_extension_map(
  122.                     missing_node, extension_node_map
  123.                 )
  124.                 if extension_url:
  125.                     print(f"  {missing_node} / {extension_url}")
  126.                 else:
  127.                     print(f"  {missing_node} / NOT FOUND")
  128.             else:
  129.                 print(f"  {missing_node} / NOT FOUND")
  130.     else:
  131.         print("  Workflow does not use custom nodes.")
  132.  
  133.  
  134. def process_workflow_dir(
  135.     dir_path, built_in_nodes, extension_node_map, current_level=0, max_levels=2
  136. ):
  137.     # Recursively process a directory of workflow JSON files.
  138.  
  139.     if current_level > max_levels:
  140.         return
  141.  
  142.     if not os.path.exists(dir_path):
  143.         print(f"Error: Directory '{dir_path}' not found.")
  144.         sys.exit(1)
  145.  
  146.     for entry in os.listdir(dir_path):
  147.         entry_path = os.path.join(dir_path, entry)
  148.         if os.path.isfile(entry_path) and entry_path.endswith(".json"):
  149.             process_workflow_json(entry_path, built_in_nodes, extension_node_map)
  150.         elif os.path.isdir(entry_path):
  151.             process_workflow_dir(
  152.                 entry_path, built_in_nodes, extension_node_map, current_level + 1
  153.             )
  154.  
  155.  
  156. def print_help():
  157.  
  158.     help_message = """
  159.    [ComfyUI Workflow Custom Nodes Checker]
  160.  
  161.    This script reads ComfyUI workflows (either a single workflow or workflows in a
  162.    directory) and displays the custom nodes the workflows require.
  163.  
  164.    Usage:
  165.    python custom_nodes_checker.py [<comfyui_path>] [<workflow_path>]
  166.  
  167.    Arguments:
  168.    <comfyui_path>   - Optional. Path to ComfyUI root directory or directly to `nodes.py` file.
  169.                       If not provided, assumes `nodes.py` is in the same directory
  170.                       as the script.
  171.    <workflow_path>  - Optional. Path to a JSON workflow file or workflows directory.
  172.                       If not provided, assumes a `workflows` directory in the same
  173.                       directory as the script.
  174.  
  175.    Options:
  176.    -h, --help       - Display this help message.
  177.  
  178.    Example:
  179.    python custom_nodes_checker.py /path/to/comfyui /path/to/workflow.json
  180.    python custom_nodes_checker.py /path/to/comfyui /path/to/directory/
  181.    python custom_nodes_checker.py
  182.    """
  183.     print(help_message)
  184.  
  185.  
  186. def main(comfyui_path=None, workflow_path=None):
  187.     """
  188.    Main function to orchestrate the processing of workflows and comparison of nodes.
  189.  
  190.    Args:
  191.    - comfyui_path (str or None): The path to the ComfyUI root directory.
  192.    - workflow_path (str or None): The path to the workflow JSON file or directory.
  193.    """
  194.     script_dir = os.path.dirname(os.path.abspath(__file__))
  195.     comfyui_path = comfyui_path if comfyui_path else script_dir
  196.     workflow_dir_path = (
  197.         workflow_path if workflow_path else os.path.join(script_dir, "workflows")
  198.     )
  199.  
  200.     built_in_nodes = get_built_in_nodes(comfyui_path)
  201.  
  202.     extension_node_map_path = os.path.join(
  203.         comfyui_path,
  204.         "custom_nodes",
  205.         "ComfyUI-Manager",
  206.         "node_db",
  207.         "new",
  208.         "extension-node-map.json",
  209.     )
  210.     extension_node_map = load_extension_node_map(extension_node_map_path)
  211.  
  212.     if os.path.isfile(workflow_dir_path) and workflow_dir_path.endswith(".json"):
  213.         process_workflow_json(workflow_dir_path, built_in_nodes, extension_node_map)
  214.     elif os.path.isdir(workflow_dir_path):
  215.         process_workflow_dir(workflow_dir_path, built_in_nodes, extension_node_map)
  216.     else:
  217.         print(f"Error: Provided workflow path '{workflow_dir_path}' is invalid.")
  218.         sys.exit(1)
  219.  
  220.  
  221. if __name__ == "__main__":
  222.  
  223.     if len(sys.argv) == 2 and sys.argv[1] in ("--help", "-h"):
  224.         print_help()
  225.         sys.exit(0)
  226.  
  227.     comfyui_path = sys.argv[1] if len(sys.argv) > 1 else None
  228.     workflow_path = sys.argv[2] if len(sys.argv) > 2 else None
  229.  
  230.     main(comfyui_path, workflow_path)
Tags: ComfyUI
Advertisement
Add Comment
Please, Sign In to add comment