comfy-cli 0.0.20__tar.gz → 0.0.20.dev1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/PKG-INFO +1 -1
  2. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/cmdline.py +14 -1
  3. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/command/custom_nodes/command.py +9 -18
  4. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/config_manager.py +9 -15
  5. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/constants.py +2 -0
  6. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/logging.py +1 -1
  7. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/registry/config_parser.py +8 -0
  8. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/tracking.py +50 -16
  9. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/update.py +1 -1
  10. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli.egg-info/PKG-INFO +1 -1
  11. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/pyproject.toml +1 -1
  12. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/LICENSE +0 -0
  13. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/README.md +0 -0
  14. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/__init__.py +0 -0
  15. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/__main__.py +0 -0
  16. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/command/__init__.py +0 -0
  17. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/command/custom_nodes/__init__.py +0 -0
  18. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/command/install.py +0 -0
  19. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/command/models/models.py +0 -0
  20. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/command/run.py +0 -0
  21. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/env_checker.py +0 -0
  22. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/registry/__init__.py +0 -0
  23. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/registry/api.py +0 -0
  24. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/registry/types.py +0 -0
  25. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/registry/zip.py +0 -0
  26. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/ui.py +0 -0
  27. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/utils.py +0 -0
  28. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli/workspace_manager.py +0 -0
  29. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli.egg-info/SOURCES.txt +0 -0
  30. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli.egg-info/dependency_links.txt +0 -0
  31. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli.egg-info/entry_points.txt +0 -0
  32. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli.egg-info/requires.txt +0 -0
  33. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/comfy_cli.egg-info/top_level.txt +0 -0
  34. {comfy_cli-0.0.20 → comfy_cli-0.0.20.dev1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: comfy-cli
3
- Version: 0.0.20
3
+ Version: 0.0.20.dev1
4
4
  Summary: A CLI tool for installing and using ComfyUI.
5
5
  Maintainer-email: Yoland Yan <yoland@drip.art>, James Kwon <hongilkwon316@gmail.com>, Robin Huang <robin@drip.art>, "Dr.Lt.Data" <dr.lt.data@gmail.com>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -82,10 +82,13 @@ def entry(
82
82
  help="Execute from current path",
83
83
  callback=exclusivity_callback,
84
84
  ),
85
+ yes: bool = typer.Option(
86
+ False, "--yes", "-y", help="Enable without confirmation", is_flag=True
87
+ ),
85
88
  ):
86
89
  workspace_manager.setup_workspace_manager(workspace, here, recent)
87
90
 
88
- tracking.prompt_tracking_consent()
91
+ tracking.prompt_tracking_consent(yes)
89
92
 
90
93
  if ctx.invoked_subcommand is None:
91
94
  print(
@@ -152,6 +155,14 @@ def install(
152
155
  callback=gpu_exclusivity_callback,
153
156
  ),
154
157
  ] = None,
158
+ cpu: Annotated[
159
+ bool,
160
+ typer.Option(
161
+ show_default=False,
162
+ help="Install for CPU",
163
+ callback=gpu_exclusivity_callback,
164
+ ),
165
+ ] = None,
155
166
  commit: Annotated[
156
167
  Optional[str], typer.Option(help="Specify commit hash for ComfyUI")
157
168
  ] = None,
@@ -203,6 +214,8 @@ def install(
203
214
  gpu = GPU_OPTION.AMD
204
215
  elif m_series:
205
216
  gpu = GPU_OPTION.M_SERIES
217
+ elif cpu:
218
+ gpu = None
206
219
  else:
207
220
  if platform == constants.OS.MACOS:
208
221
  gpu = ui.prompt_select_enum(
@@ -46,7 +46,7 @@ def execute_cm_cli(args, channel=None, mode=None):
46
46
  cmd += ["--channel", channel]
47
47
 
48
48
  if mode is not None:
49
- cmd += ["--mode", channel]
49
+ cmd += ["--mode", mode]
50
50
 
51
51
  new_env = os.environ.copy()
52
52
  session_path = os.path.join(
@@ -172,11 +172,10 @@ def show(
172
172
  ),
173
173
  channel: Annotated[
174
174
  str,
175
- "--channel",
176
175
  typer.Option(show_default=False, help="Specify the operation mode"),
177
176
  ] = None,
178
177
  mode: Annotated[
179
- str, "--mode", typer.Option(show_default=False, help="[remote|local|cache]")
178
+ str, typer.Option(show_default=False, help="[remote|local|cache]")
180
179
  ] = None,
181
180
  ):
182
181
  valid_commands = [
@@ -212,11 +211,10 @@ def simple_show(
212
211
  ),
213
212
  channel: Annotated[
214
213
  str,
215
- "--channel",
216
214
  typer.Option(show_default=False, help="Specify the operation mode"),
217
215
  ] = None,
218
216
  mode: Annotated[
219
- str, "--mode", typer.Option(show_default=False, help="[remote|local|cache]")
217
+ str, typer.Option(show_default=False, help="[remote|local|cache]")
220
218
  ] = None,
221
219
  ):
222
220
  valid_commands = [
@@ -277,11 +275,10 @@ def reinstall(
277
275
  args: List[str] = typer.Argument(..., help="reinstall custom nodes"),
278
276
  channel: Annotated[
279
277
  str,
280
- "--channel",
281
278
  typer.Option(show_default=False, help="Specify the operation mode"),
282
279
  ] = None,
283
280
  mode: Annotated[
284
- str, "--mode", typer.Option(show_default=False, help="[remote|local|cache]")
281
+ str, typer.Option(show_default=False, help="[remote|local|cache]")
285
282
  ] = None,
286
283
  ):
287
284
  if "all" in args:
@@ -305,11 +302,10 @@ def uninstall(
305
302
  args: List[str] = typer.Argument(..., help="uninstall custom nodes"),
306
303
  channel: Annotated[
307
304
  str,
308
- "--channel",
309
305
  typer.Option(show_default=False, help="Specify the operation mode"),
310
306
  ] = None,
311
307
  mode: Annotated[
312
- str, "--mode", typer.Option(show_default=False, help="[remote|local|cache]")
308
+ str, typer.Option(show_default=False, help="[remote|local|cache]")
313
309
  ] = None,
314
310
  ):
315
311
  if "all" in args:
@@ -336,11 +332,10 @@ def update(
336
332
  args: List[str] = typer.Argument(..., help="update custom nodes"),
337
333
  channel: Annotated[
338
334
  str,
339
- "--channel",
340
335
  typer.Option(show_default=False, help="Specify the operation mode"),
341
336
  ] = None,
342
337
  mode: Annotated[
343
- str, "--mode", typer.Option(show_default=False, help="[remote|local|cache]")
338
+ str, typer.Option(show_default=False, help="[remote|local|cache]")
344
339
  ] = None,
345
340
  ):
346
341
  valid_modes = ["remote", "local", "cache"]
@@ -360,11 +355,10 @@ def disable(
360
355
  args: List[str] = typer.Argument(..., help="disable custom nodes"),
361
356
  channel: Annotated[
362
357
  str,
363
- "--channel",
364
358
  typer.Option(show_default=False, help="Specify the operation mode"),
365
359
  ] = None,
366
360
  mode: Annotated[
367
- str, "--mode", typer.Option(show_default=False, help="[remote|local|cache]")
361
+ str, typer.Option(show_default=False, help="[remote|local|cache]")
368
362
  ] = None,
369
363
  ):
370
364
  valid_modes = ["remote", "local", "cache"]
@@ -384,11 +378,10 @@ def enable(
384
378
  args: List[str] = typer.Argument(..., help="enable custom nodes"),
385
379
  channel: Annotated[
386
380
  str,
387
- "--channel",
388
381
  typer.Option(show_default=False, help="Specify the operation mode"),
389
382
  ] = None,
390
383
  mode: Annotated[
391
- str, "--mode", typer.Option(show_default=False, help="[remote|local|cache]")
384
+ str, typer.Option(show_default=False, help="[remote|local|cache]")
392
385
  ] = None,
393
386
  ):
394
387
  valid_modes = ["remote", "local", "cache"]
@@ -410,11 +403,10 @@ def fix(
410
403
  ),
411
404
  channel: Annotated[
412
405
  str,
413
- "--channel",
414
406
  typer.Option(show_default=False, help="Specify the operation mode"),
415
407
  ] = None,
416
408
  mode: Annotated[
417
- str, "--mode", typer.Option(show_default=False, help="[remote|local|cache]")
409
+ str, typer.Option(show_default=False, help="[remote|local|cache]")
418
410
  ] = None,
419
411
  ):
420
412
  valid_modes = ["remote", "local", "cache"]
@@ -500,7 +492,6 @@ def deps_in_workflow(
500
492
  ],
501
493
  channel: Annotated[
502
494
  str,
503
- "--channel",
504
495
  typer.Option(show_default=False, help="Specify the operation mode"),
505
496
  ] = None,
506
497
  mode: Annotated[
@@ -1,11 +1,10 @@
1
1
  import configparser
2
2
  import os
3
3
 
4
- import tomlkit
5
-
6
4
  from comfy_cli.utils import singleton, get_os, is_running
7
5
  from comfy_cli import constants, logging
8
6
  from typing import Optional, Tuple
7
+ from importlib.metadata import version
9
8
 
10
9
 
11
10
  @singleton
@@ -19,11 +18,6 @@ class ConfigManager(object):
19
18
  def get_config_path():
20
19
  return constants.DEFAULT_CONFIG[get_os()]
21
20
 
22
- @staticmethod
23
- def get_pyproject_path():
24
- # TODO: check if this works for homebrew and pip installed comfy-cli as well.
25
- return os.path.join(os.path.dirname(__file__), "../pyproject.toml")
26
-
27
21
  def get_config_file_path(self):
28
22
  return os.path.join(self.get_config_path(), "config.ini")
29
23
 
@@ -125,13 +119,13 @@ class ConfigManager(object):
125
119
  self.background = None
126
120
 
127
121
  def get_cli_version(self):
122
+ # Note: this approach should work for users installing the CLI via PyPi (e.g., pip install comfy-cli)
128
123
  try:
129
- with open(self.get_pyproject_path(), "r") as f:
130
- pyproject_toml_content = f.read()
131
- parsed_toml = tomlkit.parse(pyproject_toml_content)
132
- version = parsed_toml["project"]["version"]
133
- return version
124
+ return version("comfy-cli")
134
125
  except Exception as e:
135
- # Handle exceptions when parsing or retrieving the version
136
- logging.error(f"Error occurred while retrieving CLI version: {e}")
137
- return None
126
+ logging.debug(
127
+ f"Error occurred while retrieving CLI version using importlib.metadata: {e}"
128
+ )
129
+
130
+ # TODO: cover the users installing the CLI via homebrew
131
+ return "0.0.0"
@@ -34,6 +34,8 @@ CONFIG_KEY_DEFAULT_WORKSPACE = "default_workspace"
34
34
  CONFIG_KEY_DEFAULT_LAUNCH_EXTRAS = "default_launch_extras"
35
35
  CONFIG_KEY_RECENT_WORKSPACE = "recent_workspace"
36
36
  CONFIG_KEY_ENABLE_TRACKING = "enable_tracking"
37
+ CONFIG_KEY_USER_ID = "user_id"
38
+ CONFIG_KEY_INSTALL_EVENT_TRIGGERED = "install_event_triggered"
37
39
  CONFIG_KEY_BACKGROUND = "background"
38
40
 
39
41
  COMFY_LOCK_YAML_FILE = "comfy.lock.yaml"
@@ -19,7 +19,7 @@ def setup_logging():
19
19
  "ERROR": logging.ERROR,
20
20
  "CRITICAL": logging.CRITICAL,
21
21
  }
22
- log_level_key = os.getenv("LOG_LEVEL", "WARN").upper()
22
+ log_level_key = os.getenv("LOG_LEVEL", "ERROR").upper()
23
23
  logging.basicConfig(
24
24
  level=log_levels.get(log_level_key, logging.WARNING),
25
25
  format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
@@ -72,7 +72,15 @@ def initialize_project_config():
72
72
  "Could not retrieve Git remote URL. Are you in a Git repository?"
73
73
  )
74
74
 
75
+ # Convert SSH URL to HTTPS if needed
76
+ if git_remote_url.startswith("git@github.com:"):
77
+ git_remote_url = git_remote_url.replace(
78
+ "git@github.com:", "https://github.com/"
79
+ )
80
+
81
+ # Ensure the URL ends with `.git` and remove it to obtain the plain URL
75
82
  repo_name = git_remote_url.split("/")[-1].replace(".git", "")
83
+ git_remote_url = git_remote_url.replace(".git", "")
76
84
 
77
85
  project = document.get("project", tomlkit.table())
78
86
  urls = project.get("urls", tomlkit.table())
@@ -1,10 +1,11 @@
1
1
  import functools
2
+ import logging as logginglib
2
3
  import os
3
4
  import uuid
4
- import logging as logginglib
5
- from mixpanel import Mixpanel, MixpanelException
6
5
 
7
6
  import typer
7
+ from mixpanel import Mixpanel
8
+
8
9
  from comfy_cli import logging, ui, constants
9
10
  from comfy_cli.config_manager import ConfigManager
10
11
 
@@ -13,12 +14,15 @@ logginglib.getLogger("urllib3").setLevel(logginglib.ERROR)
13
14
 
14
15
  MIXPANEL_TOKEN = "93aeab8962b622d431ac19800ccc9f67"
15
16
  DISABLE_TELEMETRY = os.getenv("DISABLE_TELEMETRY", False)
16
- PROJECT_CONFIG_PATH = os.path.join(os.path.dirname(__file__), "pyproject.toml")
17
17
  mp = Mixpanel(MIXPANEL_TOKEN) if MIXPANEL_TOKEN else None
18
18
 
19
19
  # Generate a unique tracing ID per command.
20
20
  config_manager = ConfigManager()
21
21
  cli_version = config_manager.get_cli_version()
22
+
23
+ # tracking all events for a single user
24
+ user_id = config_manager.get(constants.CONFIG_KEY_USER_ID)
25
+ # tracking all events for a single command
22
26
  tracing_id = str(uuid.uuid4())
23
27
 
24
28
  app = typer.Typer()
@@ -28,6 +32,7 @@ app = typer.Typer()
28
32
  def enable():
29
33
  set_tracking_enabled(True)
30
34
  typer.echo(f"Tracking is now {'enabled' if enable else 'disabled'}.")
35
+ init_tracking(True)
31
36
 
32
37
 
33
38
  @app.command()
@@ -37,16 +42,19 @@ def disable():
37
42
 
38
43
 
39
44
  def track_event(event_name: str, properties: any = {}):
45
+ logging.debug(
46
+ f"tracking event called with event_name: {event_name} and properties: {properties}"
47
+ )
40
48
  enable_tracking = config_manager.get(constants.CONFIG_KEY_ENABLE_TRACKING)
41
- if enable_tracking:
49
+ if not enable_tracking:
50
+ return
51
+
52
+ try:
42
53
  properties["cli_version"] = cli_version
43
- try:
44
- mp.track(distinct_id=tracing_id, event_name=event_name, properties=properties)
45
- except MixpanelException as e:
46
- # Ignore errors due to lack of internet.
47
- return
48
- except Exception as e:
49
- logging.error(f"Failed to track event: {e}")
54
+ properties["tracing_id"] = tracing_id
55
+ mp.track(distinct_id=user_id, event_name=event_name, properties=properties)
56
+ except Exception as e:
57
+ logging.warning(f"Failed to track event: {e}") # Log the error but do not raise
50
58
 
51
59
 
52
60
  def track_command(sub_command: str = None):
@@ -81,19 +89,45 @@ def track_command(sub_command: str = None):
81
89
  return decorator
82
90
 
83
91
 
84
- def prompt_tracking_consent():
92
+ def prompt_tracking_consent(yes: bool = False):
85
93
  tracking_enabled = config_manager.get(constants.CONFIG_KEY_ENABLE_TRACKING)
86
94
  if tracking_enabled is not None:
87
95
  return
88
96
 
89
- enable_tracking = ui.prompt_confirm_action(
90
- "Do you agree to enable tracking to improve the application?"
91
- )
97
+ if yes:
98
+ init_tracking(True)
99
+ else:
100
+ enable_tracking = ui.prompt_confirm_action(
101
+ "Do you agree to enable tracking to improve the application?"
102
+ )
103
+ init_tracking(enable_tracking)
104
+
105
+
106
+ def init_tracking(enable_tracking: bool):
107
+ """
108
+ Initialize the tracking system by setting the user identifier and tracking enabled status.
109
+ """
110
+ logging.debug(f"Initializing tracking with enable_tracking: {enable_tracking}")
92
111
  config_manager.set(constants.CONFIG_KEY_ENABLE_TRACKING, str(enable_tracking))
112
+ if not enable_tracking:
113
+ return
114
+
115
+ user_id = config_manager.get(constants.CONFIG_KEY_USER_ID)
116
+ logging.debug(f'User identifier for tracking user_id found: {user_id}."')
117
+ if user_id is None:
118
+ user_id = str(uuid.uuid4())
119
+ config_manager.set(constants.CONFIG_KEY_USER_ID, user_id)
120
+ logging.debug(f'Setting user identifier for tracking user_id: {user_id}."')
93
121
 
94
122
  # Note: only called once when the user interacts with the CLI for the
95
123
  # first time iff the permission is granted.
96
- track_event("install")
124
+ install_event_triggered = config_manager.get(
125
+ constants.CONFIG_KEY_INSTALL_EVENT_TRIGGERED
126
+ )
127
+ if not install_event_triggered:
128
+ logging.debug("Tracking install event.")
129
+ config_manager.set(constants.CONFIG_KEY_INSTALL_EVENT_TRIGGERED, "True")
130
+ track_event("install")
97
131
 
98
132
 
99
133
  def set_tracking_enabled(enabled: bool):
@@ -16,7 +16,7 @@ def check_for_newer_pypi_version(package_name, current_version):
16
16
  latest_version = response.json()["info"]["version"]
17
17
  return latest_version != current_version, latest_version
18
18
  except requests.RequestException as e:
19
- #print(f"Error checking latest version: {e}")
19
+ # print(f"Error checking latest version: {e}")
20
20
  return False, current_version
21
21
 
22
22
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: comfy-cli
3
- Version: 0.0.20
3
+ Version: 0.0.20.dev1
4
4
  Summary: A CLI tool for installing and using ComfyUI.
5
5
  Maintainer-email: Yoland Yan <yoland@drip.art>, James Kwon <hongilkwon316@gmail.com>, Robin Huang <robin@drip.art>, "Dr.Lt.Data" <dr.lt.data@gmail.com>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "comfy-cli"
7
7
  license = {file = "LICENSE"}
8
- version = "v0.0.20" # Will be filled in by the CI/CD pipeline. Check publish_package.py.
8
+ version = "0.0.20.dev1" # Will be filled in by the CI/CD pipeline. Check publish_package.py.
9
9
  requires-python = ">= 3.9"
10
10
  description = "A CLI tool for installing and using ComfyUI."
11
11
  readme = "README.md"
File without changes
File without changes
File without changes