From 8d9f576974101dd3432b8080c1e54e60eb28225b Mon Sep 17 00:00:00 2001 From: Robin Huang Date: Mon, 29 Jul 2024 14:46:09 -0700 Subject: [PATCH 1/7] Support new license format. --- comfy_cli/cmdline.py | 6 +- comfy_cli/command/install.py | 7 +- comfy_cli/registry/api.py | 19 +++- comfy_cli/registry/config_parser.py | 16 ++- comfy_cli/registry/types.py | 7 +- comfy_cli/workspace_manager.py | 36 ++++--- tests/comfy_cli/registry/test_api.py | 4 +- .../comfy_cli/registry/test_config_parser.py | 99 +++++++++++++++++++ 8 files changed, 163 insertions(+), 31 deletions(-) create mode 100644 tests/comfy_cli/registry/test_config_parser.py diff --git a/comfy_cli/cmdline.py b/comfy_cli/cmdline.py index 7dafc5e..5724f9d 100644 --- a/comfy_cli/cmdline.py +++ b/comfy_cli/cmdline.py @@ -9,8 +9,8 @@ from rich import print from rich.console import Console from typing_extensions import Annotated, List - -from comfy_cli import constants, env_checker, logging, tracking, ui, utils +import ui +from comfy_cli import constants, env_checker, logging, tracking, utils from comfy_cli.command import custom_nodes from comfy_cli.command import install as install_inner from comfy_cli.command import run as run_inner @@ -334,7 +334,7 @@ def update( "comfy", help="[all|comfy]", autocompletion=utils.create_choice_completer(["all", "comfy"]), - ) + ), ): if target not in ["all", "comfy"]: typer.echo( diff --git a/comfy_cli/command/install.py b/comfy_cli/command/install.py index 54592df..26a8e84 100644 --- a/comfy_cli/command/install.py +++ b/comfy_cli/command/install.py @@ -10,6 +10,7 @@ from comfy_cli.command.custom_nodes.command import update_node_id_cache from comfy_cli.constants import GPU_OPTION from comfy_cli.workspace_manager import WorkspaceManager, check_comfy_repo +from typing import Optional workspace_manager = WorkspaceManager() @@ -22,7 +23,7 @@ def get_os_details(): def install_comfyui_dependencies( repo_dir, - gpu: GPU_OPTION, + gpu: Optional[GPU_OPTION], plat: constants.OS, cuda_version: constants.CUDAVersion, skip_torch_or_directml: bool, @@ -163,10 +164,10 @@ def execute( comfy_path: str, restore: bool, skip_manager: bool, + plat: constants.OS, commit=None, - gpu: constants.GPU_OPTION = None, + gpu: Optional[constants.GPU_OPTION] = None, cuda_version: constants.CUDAVersion = constants.CUDAVersion.v12_1, - plat: constants.OS = None, skip_torch_or_directml: bool = False, skip_requirement: bool = False, *args, diff --git a/comfy_cli/registry/api.py b/comfy_cli/registry/api.py index c8d72e0..6bde36c 100644 --- a/comfy_cli/registry/api.py +++ b/comfy_cli/registry/api.py @@ -5,7 +5,7 @@ import requests # Reduced global imports from comfy_cli.registry -from comfy_cli.registry.types import Node, NodeVersion, PublishNodeVersionResponse +from comfy_cli.registry.types import Node, NodeVersion, PublishNodeVersionResponse, PyProjectConfig, License class RegistryAPI: @@ -17,11 +17,11 @@ def determine_base_url(self): if env == "dev": return "http://localhost:8080" elif env == "staging": - return "https://staging.comfyregistry.org" + return "https://stagingapi.comfy.org" else: return "https://api.comfy.org" - def publish_node_version(self, node_config, token) -> PublishNodeVersionResponse: + def publish_node_version(self, node_config: PyProjectConfig, token) -> PublishNodeVersionResponse: """ Publishes a new version of a node. @@ -33,7 +33,7 @@ def publish_node_version(self, node_config, token) -> PublishNodeVersionResponse PublishNodeVersionResponse: The response object from the API server. """ # Local import to prevent circular dependency - + print(self.determine_base_url()) if not node_config.tool_comfy.publisher_id: raise Exception( "Publisher ID is required in pyproject.toml to publish a node version" @@ -43,6 +43,7 @@ def publish_node_version(self, node_config, token) -> PublishNodeVersionResponse raise Exception( "Project name is required in pyproject.toml to publish a node version" ) + license_json = serialize_license(node_config.project.license) url = f"{self.base_url}/publishers/{node_config.tool_comfy.publisher_id}/nodes/{node_config.project.name}/versions" headers = {"Content-Type": "application/json"} @@ -53,7 +54,7 @@ def publish_node_version(self, node_config, token) -> PublishNodeVersionResponse "description": node_config.project.description, "icon": node_config.tool_comfy.icon, "name": node_config.tool_comfy.display_name, - "license": node_config.project.license, + "license": license_json, "repository": node_config.project.urls.repository, }, "node_version": { @@ -177,3 +178,11 @@ def map_node_to_node_class(api_node_data): else None ), ) + + +def serialize_license(license: License) -> dict: + if license.file: + return {"file": license.file} + if license.text: + return {"text": license.text} + return {} \ No newline at end of file diff --git a/comfy_cli/registry/config_parser.py b/comfy_cli/registry/config_parser.py index 81dc3b1..9094593 100644 --- a/comfy_cli/registry/config_parser.py +++ b/comfy_cli/registry/config_parser.py @@ -11,6 +11,7 @@ Model, ProjectConfig, PyProjectConfig, + License, URLs, ) @@ -140,13 +141,24 @@ def extract_node_configuration( urls_data = project_data.get("urls", {}) comfy_data = data.get("tool", {}).get("comfy", {}) + license_data = project_data.get("license", {}) + if isinstance(license_data, str): + license = License(text=license_data) + elif isinstance(license_data, dict): + license = License( + file=license_data.get("file", ""), + text=license_data.get("text", "") + ) + else: + license = License() + project = ProjectConfig( name=project_data.get("name", ""), description=project_data.get("description", ""), version=project_data.get("version", ""), - requires_python=project_data.get("requires-pyton", ""), + requires_python=project_data.get("requires-python", ""), dependencies=project_data.get("dependencies", []), - license=project_data.get("license", ""), + license=license, urls=URLs( homepage=urls_data.get("Homepage", ""), documentation=urls_data.get("Documentation", ""), diff --git a/comfy_cli/registry/types.py b/comfy_cli/registry/types.py index 1b355bd..f33c06d 100644 --- a/comfy_cli/registry/types.py +++ b/comfy_cli/registry/types.py @@ -52,7 +52,10 @@ class ComfyConfig: icon: str = "" models: List[Model] = field(default_factory=list) - +@dataclass +class License: + file: str = "" + text: str = "" @dataclass class ProjectConfig: name: str = "" @@ -60,7 +63,7 @@ class ProjectConfig: version: str = "1.0.0" requires_python: str = ">= 3.9" dependencies: List[str] = field(default_factory=list) - license: str = "" + license: License = field(default_factory=License) urls: URLs = field(default_factory=URLs) diff --git a/comfy_cli/workspace_manager.py b/comfy_cli/workspace_manager.py index 5c8b4c1..6e97f92 100644 --- a/comfy_cli/workspace_manager.py +++ b/comfy_cli/workspace_manager.py @@ -4,7 +4,7 @@ from datetime import datetime from enum import Enum from pathlib import Path -from typing import List, Optional, Tuple +from typing import List, Optional, Tuple, Dict import git import typer @@ -33,7 +33,7 @@ class Model: @dataclass class Basics: name: Optional[str] = None - updated_at: datetime = None + updated_at: Optional[datetime] = None @dataclass @@ -79,7 +79,7 @@ def check_comfy_repo(path) -> Tuple[bool, Optional[git.Repo]]: return False, None # Not in a git repo at all # pylint: disable=E1101 # no-member - except git.exc.InvalidGitRepositoryError: + except git.InvalidGitRepositoryError: return False, None @@ -110,10 +110,14 @@ def check_comfy_repo(path) -> Tuple[bool, Optional[git.Repo]]: # Generate and update this following method using chatGPT def save_yaml(file_path: str, metadata: ComfyLockYAMLStruct): + updated_at = None + if metadata.basics.updated_at: + updated_at = metadata.basics.updated_at.isoformat() + data = { "basics": { "name": metadata.basics.name, - "updated_at": metadata.basics.updated_at.isoformat(), + "updated_at": updated_at, }, "models": [ { @@ -235,13 +239,12 @@ def get_workspace_path(self) -> Tuple[str, WorkspaceType]: if self.use_here is True: current_directory = os.getcwd() found_comfy_repo, comfy_repo = check_comfy_repo(current_directory) - if found_comfy_repo: - return comfy_repo.working_dir, WorkspaceType.CURRENT_DIR - else: - return ( - os.path.join(current_directory, "ComfyUI"), - WorkspaceType.CURRENT_DIR, - ) + if found_comfy_repo and comfy_repo: + return str(comfy_repo.working_dir), WorkspaceType.CURRENT_DIR + return ( + os.path.join(current_directory, "ComfyUI"), + WorkspaceType.CURRENT_DIR, + ) # Check the current directory for a ComfyUI if self.use_here is None: @@ -250,8 +253,8 @@ def get_workspace_path(self) -> Tuple[str, WorkspaceType]: os.path.join(current_directory) ) # If it's in a sub dir of the ComfyUI repo, get the repo working dir - if found_comfy_repo: - return comfy_repo.working_dir, WorkspaceType.CURRENT_DIR + if found_comfy_repo and comfy_repo: + return str(comfy_repo.working_dir), WorkspaceType.CURRENT_DIR # Check for user-set default workspace default_workspace = self.config_manager.get( @@ -324,7 +327,9 @@ def scan_dir_concur(self): return model_files - def load_metadata(self): + def load_metadata(self) -> Dict: + if self.workspace_path is None: + return {} file_path = os.path.join(self.workspace_path, constants.COMFY_LOCK_YAML_FILE) if os.path.exists(file_path): with open(file_path, "r", encoding="utf-8") as file: @@ -333,6 +338,9 @@ def load_metadata(self): return {} def save_metadata(self): + if self.workspace_path is None: + print("[bold red]warn: Workspace path not set. Skipping metadata save.[/bold red]") + return file_path = os.path.join(self.workspace_path, constants.COMFY_LOCK_YAML_FILE) save_yaml(file_path, self.metadata) diff --git a/tests/comfy_cli/registry/test_api.py b/tests/comfy_cli/registry/test_api.py index adbf3d3..5cede7c 100644 --- a/tests/comfy_cli/registry/test_api.py +++ b/tests/comfy_cli/registry/test_api.py @@ -3,7 +3,7 @@ from comfy_cli.registry import PyProjectConfig from comfy_cli.registry.api import RegistryAPI -from comfy_cli.registry.types import ComfyConfig, ProjectConfig, URLs +from comfy_cli.registry.types import ComfyConfig, ProjectConfig, URLs, License class TestRegistryAPI(unittest.TestCase): @@ -16,7 +16,7 @@ def setUp(self): version="0.1.0", requires_python=">= 3.9", dependencies=["dep1", "dep2"], - license="MIT", + license=License(file="LICENSE"), urls=URLs(repository="https://github.com/test/test_node"), ), tool_comfy=ComfyConfig( diff --git a/tests/comfy_cli/registry/test_config_parser.py b/tests/comfy_cli/registry/test_config_parser.py new file mode 100644 index 0000000..ecd7226 --- /dev/null +++ b/tests/comfy_cli/registry/test_config_parser.py @@ -0,0 +1,99 @@ +from unittest.mock import patch, mock_open +import pytest +from comfy_cli.registry.config_parser import extract_node_configuration +from comfy_cli.registry.types import ( + PyProjectConfig, + ProjectConfig, + License, + URLs, + ComfyConfig, + Model, +) + + +@pytest.fixture +def mock_toml_data(): + return { + "project": { + "name": "test-project", + "description": "A test project", + "version": "1.0.0", + "requires-python": ">=3.7", + "dependencies": ["requests"], + "license": {"file": "LICENSE"}, + "urls": { + "Homepage": "https://example.com", + "Documentation": "https://docs.example.com", + "Repository": "https://github.com/example/test-project", + "Issues": "https://github.com/example/test-project/issues", + }, + }, + "tool": { + "comfy": { + "PublisherId": "test-publisher", + "DisplayName": "Test Project", + "Icon": "icon.png", + "Models": [ + { + "location": "model1.bin", + "model_url": "https://example.com/model1", + }, + { + "location": "model2.bin", + "model_url": "https://example.com/model2", + }, + ], + } + }, + } + + +def test_extract_node_configuration_success(mock_toml_data): + with patch("os.path.isfile", return_value=True), patch( + "builtins.open", mock_open() + ), patch("tomlkit.load", return_value=mock_toml_data): + result = extract_node_configuration("fake_path.toml") + + assert isinstance(result, PyProjectConfig) + assert result.project.name == "test-project" + assert result.project.description == "A test project" + assert result.project.version == "1.0.0" + assert result.project.requires_python == ">=3.7" + assert result.project.dependencies == ["requests"] + assert result.project.license == License(file="LICENSE") + assert result.project.urls == URLs( + homepage="https://example.com", + documentation="https://docs.example.com", + repository="https://github.com/example/test-project", + issues="https://github.com/example/test-project/issues", + ) + assert result.tool_comfy.publisher_id == "test-publisher" + assert result.tool_comfy.display_name == "Test Project" + assert result.tool_comfy.icon == "icon.png" + assert len(result.tool_comfy.models) == 2 + assert result.tool_comfy.models[0] == Model( + location="model1.bin", model_url="https://example.com/model1" + ) + + +def test_extract_node_configuration_license_text(): + mock_data = { + "project": { + "license": "MIT License", + }, + } + with patch("os.path.isfile", return_value=True), patch( + "builtins.open", mock_open() + ), patch("tomlkit.load", return_value=mock_data): + result = extract_node_configuration("fake_path.toml") + assert result is not None, "Expected PyProjectConfig, got None" + assert isinstance(result, PyProjectConfig) + assert result.project.license == License(text="MIT License") + + +def test_extract_node_configuration_empty_file(): + result = extract_node_configuration("fake_path.toml") + + assert isinstance(result, PyProjectConfig) + assert result.project == ProjectConfig(license=License()) + assert result.tool_comfy == ComfyConfig() From 38b1c657068bd95f7143b6e096b7c613f994e3c8 Mon Sep 17 00:00:00 2001 From: Robin Huang Date: Mon, 29 Jul 2024 15:28:42 -0700 Subject: [PATCH 2/7] Fix. --- comfy_cli/cmdline.py | 3 +-- comfy_cli/registry/api.py | 15 +++++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/comfy_cli/cmdline.py b/comfy_cli/cmdline.py index 5724f9d..6949240 100644 --- a/comfy_cli/cmdline.py +++ b/comfy_cli/cmdline.py @@ -9,8 +9,7 @@ from rich import print from rich.console import Console from typing_extensions import Annotated, List -import ui -from comfy_cli import constants, env_checker, logging, tracking, utils +from comfy_cli import constants, env_checker, logging, tracking, utils, ui from comfy_cli.command import custom_nodes from comfy_cli.command import install as install_inner from comfy_cli.command import run as run_inner diff --git a/comfy_cli/registry/api.py b/comfy_cli/registry/api.py index 6bde36c..89ce07a 100644 --- a/comfy_cli/registry/api.py +++ b/comfy_cli/registry/api.py @@ -5,7 +5,13 @@ import requests # Reduced global imports from comfy_cli.registry -from comfy_cli.registry.types import Node, NodeVersion, PublishNodeVersionResponse, PyProjectConfig, License +from comfy_cli.registry.types import ( + Node, + NodeVersion, + PublishNodeVersionResponse, + PyProjectConfig, + License, +) class RegistryAPI: @@ -21,7 +27,9 @@ def determine_base_url(self): else: return "https://api.comfy.org" - def publish_node_version(self, node_config: PyProjectConfig, token) -> PublishNodeVersionResponse: + def publish_node_version( + self, node_config: PyProjectConfig, token + ) -> PublishNodeVersionResponse: """ Publishes a new version of a node. @@ -33,7 +41,6 @@ def publish_node_version(self, node_config: PyProjectConfig, token) -> PublishNo PublishNodeVersionResponse: The response object from the API server. """ # Local import to prevent circular dependency - print(self.determine_base_url()) if not node_config.tool_comfy.publisher_id: raise Exception( "Publisher ID is required in pyproject.toml to publish a node version" @@ -185,4 +192,4 @@ def serialize_license(license: License) -> dict: return {"file": license.file} if license.text: return {"text": license.text} - return {} \ No newline at end of file + return {} From ce5bb5235ffc72bb786894822a7991e5d1a25ad4 Mon Sep 17 00:00:00 2001 From: Robin Huang Date: Mon, 29 Jul 2024 15:30:09 -0700 Subject: [PATCH 3/7] revert. --- comfy_cli/workspace_manager.py | 36 +++++++++++++--------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/comfy_cli/workspace_manager.py b/comfy_cli/workspace_manager.py index 6e97f92..5c8b4c1 100644 --- a/comfy_cli/workspace_manager.py +++ b/comfy_cli/workspace_manager.py @@ -4,7 +4,7 @@ from datetime import datetime from enum import Enum from pathlib import Path -from typing import List, Optional, Tuple, Dict +from typing import List, Optional, Tuple import git import typer @@ -33,7 +33,7 @@ class Model: @dataclass class Basics: name: Optional[str] = None - updated_at: Optional[datetime] = None + updated_at: datetime = None @dataclass @@ -79,7 +79,7 @@ def check_comfy_repo(path) -> Tuple[bool, Optional[git.Repo]]: return False, None # Not in a git repo at all # pylint: disable=E1101 # no-member - except git.InvalidGitRepositoryError: + except git.exc.InvalidGitRepositoryError: return False, None @@ -110,14 +110,10 @@ def check_comfy_repo(path) -> Tuple[bool, Optional[git.Repo]]: # Generate and update this following method using chatGPT def save_yaml(file_path: str, metadata: ComfyLockYAMLStruct): - updated_at = None - if metadata.basics.updated_at: - updated_at = metadata.basics.updated_at.isoformat() - data = { "basics": { "name": metadata.basics.name, - "updated_at": updated_at, + "updated_at": metadata.basics.updated_at.isoformat(), }, "models": [ { @@ -239,12 +235,13 @@ def get_workspace_path(self) -> Tuple[str, WorkspaceType]: if self.use_here is True: current_directory = os.getcwd() found_comfy_repo, comfy_repo = check_comfy_repo(current_directory) - if found_comfy_repo and comfy_repo: - return str(comfy_repo.working_dir), WorkspaceType.CURRENT_DIR - return ( - os.path.join(current_directory, "ComfyUI"), - WorkspaceType.CURRENT_DIR, - ) + if found_comfy_repo: + return comfy_repo.working_dir, WorkspaceType.CURRENT_DIR + else: + return ( + os.path.join(current_directory, "ComfyUI"), + WorkspaceType.CURRENT_DIR, + ) # Check the current directory for a ComfyUI if self.use_here is None: @@ -253,8 +250,8 @@ def get_workspace_path(self) -> Tuple[str, WorkspaceType]: os.path.join(current_directory) ) # If it's in a sub dir of the ComfyUI repo, get the repo working dir - if found_comfy_repo and comfy_repo: - return str(comfy_repo.working_dir), WorkspaceType.CURRENT_DIR + if found_comfy_repo: + return comfy_repo.working_dir, WorkspaceType.CURRENT_DIR # Check for user-set default workspace default_workspace = self.config_manager.get( @@ -327,9 +324,7 @@ def scan_dir_concur(self): return model_files - def load_metadata(self) -> Dict: - if self.workspace_path is None: - return {} + def load_metadata(self): file_path = os.path.join(self.workspace_path, constants.COMFY_LOCK_YAML_FILE) if os.path.exists(file_path): with open(file_path, "r", encoding="utf-8") as file: @@ -338,9 +333,6 @@ def load_metadata(self) -> Dict: return {} def save_metadata(self): - if self.workspace_path is None: - print("[bold red]warn: Workspace path not set. Skipping metadata save.[/bold red]") - return file_path = os.path.join(self.workspace_path, constants.COMFY_LOCK_YAML_FILE) save_yaml(file_path, self.metadata) From 1dc35f4800eb68553313265afad1a5561ec9d398 Mon Sep 17 00:00:00 2001 From: Robin Huang Date: Mon, 29 Jul 2024 15:30:45 -0700 Subject: [PATCH 4/7] revert. --- comfy_cli/command/install.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/comfy_cli/command/install.py b/comfy_cli/command/install.py index 26a8e84..54592df 100644 --- a/comfy_cli/command/install.py +++ b/comfy_cli/command/install.py @@ -10,7 +10,6 @@ from comfy_cli.command.custom_nodes.command import update_node_id_cache from comfy_cli.constants import GPU_OPTION from comfy_cli.workspace_manager import WorkspaceManager, check_comfy_repo -from typing import Optional workspace_manager = WorkspaceManager() @@ -23,7 +22,7 @@ def get_os_details(): def install_comfyui_dependencies( repo_dir, - gpu: Optional[GPU_OPTION], + gpu: GPU_OPTION, plat: constants.OS, cuda_version: constants.CUDAVersion, skip_torch_or_directml: bool, @@ -164,10 +163,10 @@ def execute( comfy_path: str, restore: bool, skip_manager: bool, - plat: constants.OS, commit=None, - gpu: Optional[constants.GPU_OPTION] = None, + gpu: constants.GPU_OPTION = None, cuda_version: constants.CUDAVersion = constants.CUDAVersion.v12_1, + plat: constants.OS = None, skip_torch_or_directml: bool = False, skip_requirement: bool = False, *args, From 9c4eb56ffa2ad447c8956ac9789b79372cf8bbcc Mon Sep 17 00:00:00 2001 From: Robin Huang Date: Mon, 29 Jul 2024 15:37:53 -0700 Subject: [PATCH 5/7] Add warning. --- comfy_cli/registry/config_parser.py | 14 ++++++++---- .../comfy_cli/registry/test_config_parser.py | 22 ++++++++++++++----- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/comfy_cli/registry/config_parser.py b/comfy_cli/registry/config_parser.py index 9094593..bc3a4d9 100644 --- a/comfy_cli/registry/config_parser.py +++ b/comfy_cli/registry/config_parser.py @@ -1,6 +1,7 @@ import os import subprocess from typing import Optional +import typer import tomlkit import tomlkit.exceptions @@ -145,10 +146,15 @@ def extract_node_configuration( if isinstance(license_data, str): license = License(text=license_data) elif isinstance(license_data, dict): - license = License( - file=license_data.get("file", ""), - text=license_data.get("text", "") - ) + if "file" in license_data or "text" in license_data: + license = License( + file=license_data.get("file", ""), text=license_data.get("text", "") + ) + else: + typer.echo( + "Warning: License dictionary does not contain 'file' or 'text' keys. Please check the documentation: https://docs.comfy.org/registry/specifications." + ) + license = License() else: license = License() diff --git a/tests/comfy_cli/registry/test_config_parser.py b/tests/comfy_cli/registry/test_config_parser.py index ecd7226..2108a13 100644 --- a/tests/comfy_cli/registry/test_config_parser.py +++ b/tests/comfy_cli/registry/test_config_parser.py @@ -91,9 +91,21 @@ def test_extract_node_configuration_license_text(): assert result.project.license == License(text="MIT License") -def test_extract_node_configuration_empty_file(): - result = extract_node_configuration("fake_path.toml") +def test_extract_node_configuration_license_text_dict(): + mock_data = { + "project": { + "license": { + "text": "MIT License\n\nCopyright (c) 2023 Example Corp\n\nPermission is hereby granted..." + }, + }, + } + with patch("os.path.isfile", return_value=True), patch( + "builtins.open", mock_open() + ), patch("tomlkit.load", return_value=mock_data): + result = extract_node_configuration("fake_path.toml") - assert isinstance(result, PyProjectConfig) - assert result.project == ProjectConfig(license=License()) - assert result.tool_comfy == ComfyConfig() + assert result is not None, "Expected PyProjectConfig, got None" + assert isinstance(result, PyProjectConfig) + assert result.project.license == License( + text="MIT License\n\nCopyright (c) 2023 Example Corp\n\nPermission is hereby granted..." + ) From 74ec57636fae11fb67bc31954eb2f3af697299e8 Mon Sep 17 00:00:00 2001 From: Robin Huang Date: Mon, 29 Jul 2024 15:56:35 -0700 Subject: [PATCH 6/7] Handle deprecated field. --- comfy_cli/registry/api.py | 17 +++++++++-------- comfy_cli/registry/config_parser.py | 3 +++ tests/comfy_cli/registry/test_config_parser.py | 14 ++++++++++++++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/comfy_cli/registry/api.py b/comfy_cli/registry/api.py index 89ce07a..943e011 100644 --- a/comfy_cli/registry/api.py +++ b/comfy_cli/registry/api.py @@ -51,10 +51,7 @@ def publish_node_version( "Project name is required in pyproject.toml to publish a node version" ) license_json = serialize_license(node_config.project.license) - - url = f"{self.base_url}/publishers/{node_config.tool_comfy.publisher_id}/nodes/{node_config.project.name}/versions" - headers = {"Content-Type": "application/json"} - body = { + request_body = { "personal_access_token": token, "node": { "id": node_config.project.name, @@ -69,6 +66,10 @@ def publish_node_version( "dependencies": node_config.project.dependencies, }, } + print(request_body) + url = f"{self.base_url}/publishers/{node_config.tool_comfy.publisher_id}/nodes/{node_config.project.name}/versions" + headers = {"Content-Type": "application/json"} + body = request_body response = requests.post(url, headers=headers, data=json.dumps(body)) @@ -187,9 +188,9 @@ def map_node_to_node_class(api_node_data): ) -def serialize_license(license: License) -> dict: +def serialize_license(license: License) -> str: if license.file: - return {"file": license.file} + return json.dumps({"file": license.file}) if license.text: - return {"text": license.text} - return {} + return json.dumps({"text": license.text}) + return "{}" diff --git a/comfy_cli/registry/config_parser.py b/comfy_cli/registry/config_parser.py index bc3a4d9..23cec3b 100644 --- a/comfy_cli/registry/config_parser.py +++ b/comfy_cli/registry/config_parser.py @@ -157,6 +157,9 @@ def extract_node_configuration( license = License() else: license = License() + typer.echo( + "Warning: License dictionary does not contain 'file' or 'text' keys. Please check the documentation: https://docs.comfy.org/registry/specifications." + ) project = ProjectConfig( name=project_data.get("name", ""), diff --git a/tests/comfy_cli/registry/test_config_parser.py b/tests/comfy_cli/registry/test_config_parser.py index 2108a13..4b2fb30 100644 --- a/tests/comfy_cli/registry/test_config_parser.py +++ b/tests/comfy_cli/registry/test_config_parser.py @@ -109,3 +109,17 @@ def test_extract_node_configuration_license_text_dict(): assert result.project.license == License( text="MIT License\n\nCopyright (c) 2023 Example Corp\n\nPermission is hereby granted..." ) + + +def test_extract_license_incorrect_format(): + mock_data = { + "project": {"license": "MIT"}, + } + with patch("os.path.isfile", return_value=True), patch( + "builtins.open", mock_open() + ), patch("tomlkit.load", return_value=mock_data): + result = extract_node_configuration("fake_path.toml") + + assert result is not None, "Expected PyProjectConfig, got None" + assert isinstance(result, PyProjectConfig) + assert result.project.license == License(text="MIT") From 5cce1bbf12e72ebdc7fef375018ec8bbadcc1f76 Mon Sep 17 00:00:00 2001 From: Robin Huang Date: Mon, 29 Jul 2024 15:58:15 -0700 Subject: [PATCH 7/7] Improve error message. --- comfy_cli/registry/config_parser.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/comfy_cli/registry/config_parser.py b/comfy_cli/registry/config_parser.py index 23cec3b..d61522b 100644 --- a/comfy_cli/registry/config_parser.py +++ b/comfy_cli/registry/config_parser.py @@ -145,6 +145,9 @@ def extract_node_configuration( license_data = project_data.get("license", {}) if isinstance(license_data, str): license = License(text=license_data) + typer.echo( + 'Warning: License should be in one of these two formats: license = {file = "LICENSE"} OR license = {text = "MIT License"}. Please check the documentation: https://docs.comfy.org/registry/specifications.' + ) elif isinstance(license_data, dict): if "file" in license_data or "text" in license_data: license = License( @@ -152,13 +155,13 @@ def extract_node_configuration( ) else: typer.echo( - "Warning: License dictionary does not contain 'file' or 'text' keys. Please check the documentation: https://docs.comfy.org/registry/specifications." + 'Warning: License should be in one of these two formats: license = {file = "LICENSE"} OR license = {text = "MIT License"}. Please check the documentation: https://docs.comfy.org/registry/specifications.' ) license = License() else: license = License() typer.echo( - "Warning: License dictionary does not contain 'file' or 'text' keys. Please check the documentation: https://docs.comfy.org/registry/specifications." + 'Warning: License should be in one of these two formats: license = {file = "LICENSE"} OR license = {text = "MIT License"}. Please check the documentation: https://docs.comfy.org/registry/specifications.' ) project = ProjectConfig(