Repository: dagster-io/dagster
Pull request #28845: [dg] Get cli plumbing working for new --format argument
Author: login: schrockn
Created: 2025-03-28T14:54:17Z | Merged: 2025-03-28T18:31:53Z

## Summary & Motivation

Just getting the double layer cli layering working before implementing the business logic.

* `dg` has a flag (`--format`) that defaults to `yaml`)
* `dagster_componets` has a non-optional flag (`--scaffold-format`). Renamed to avoid collision with python built-in `format`.

## How I Tested These Changes

```
(dagster-dev-3.11.11-2024-12-08) ➜  standalone_project dg scaffold dagster_components.dagster.DefinitionsComponent test_component_1 --format python
Using /Users/schrockn/code/scratch/dg-workspaces/standalone_project/.venv/bin/dagster-components
Traceback (most recent call last):
  File "/Users/schrockn/code/scratch/dg-workspaces/standalone_project/.venv/bin/dagster-components", line 10, in <module>
    sys.exit(main())
             ^^^^^^
  File "/Users/schrockn/code/dagster/python_modules/libraries/dagster-components/dagster_components/cli/__init__.py", line 35, in main
    cli(auto_envvar_prefix=ENV_PREFIX)
  File "/Users/schrockn/code/scratch/dg-workspaces/standalone_project/.venv/lib/python3.11/site-packages/click/core.py", line 1161, in __call__
    return self.main(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/schrockn/code/scratch/dg-workspaces/standalone_project/.venv/lib/python3.11/site-packages/click/core.py", line 1082, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "/Users/schrockn/code/scratch/dg-workspaces/standalone_project/.venv/lib/python3.11/site-packages/click/core.py", line 1697, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/schrockn/code/scratch/dg-workspaces/standalone_project/.venv/lib/python3.11/site-packages/click/core.py", line 1697, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/schrockn/code/scratch/dg-workspaces/standalone_project/.venv/lib/python3.11/site-packages/click/core.py", line 1443, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/schrockn/code/scratch/dg-workspaces/standalone_project/.venv/lib/python3.11/site-packages/click/core.py", line 788, in invoke
    return __callback(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/schrockn/code/dagster/python_modules/libraries/dagster-components/dagster_components/cli/scaffold.py", line 47, in scaffold_object_command
    scaffold_object(path, obj, typename, scaffold_params, scaffold_format)
  File "/Users/schrockn/code/dagster/python_modules/libraries/dagster-components/dagster_components/component_scaffolding.py", line 65, in scaffold_object
    scaffolder.scaffold(
  File "/Users/schrockn/code/dagster/python_modules/libraries/dagster-components/dagster_components/lib/definitions_component/scaffolder.py", line 33, in scaffold
    scaffold_component(
  File "/Users/schrockn/code/dagster/python_modules/libraries/dagster-components/dagster_components/component_scaffolding.py", line 37, in scaffold_component
    raise NotImplementedError("Python scaffolding not yet implemented.")
NotImplementedError: Python scaffolding not yet implemented.
An error occurred while executing a `dagster-components` command in the Python environment at /Users/schrockn/code/scratch/dg-workspaces/standalone_project/.venv.

`uv run dagster-components scaffold object dagster_components.dagster.DefinitionsComponent /Users/schrockn/code/scratch/dg-workspaces/standalone_project/standalone_project/defs/test_component_1 --scaffold-format python` exited with code 1. Aborting.
(dagster-dev-3.11.11-2024-12-08) ➜  standalone_project
```
## Changelog

> Insert changelog entry or delete this section.



Diff:
diff --git a/python_modules/libraries/dagster-components/dagster_components/cli/scaffold.py b/python_modules/libraries/dagster-components/dagster_components/cli/scaffold.py
index 38fb9f23c4ecc..02de85ccfd4d7 100644
--- a/python_modules/libraries/dagster-components/dagster_components/cli/scaffold.py
+++ b/python_modules/libraries/dagster-components/dagster_components/cli/scaffold.py
@@ -19,7 +19,17 @@ def scaffold_cli() -> None:
 @click.argument("typename", type=str)
 @click.argument("path", type=Path)
 @click.option("--json-params", type=str, default=None)
-def scaffold_object_command(typename: str, path: Path, json_params: Optional[str]) -> None:
+@click.option(
+    "--scaffold-format",
+    type=click.Choice(["yaml", "python"], case_sensitive=False),
+    help="Format of the component configuration (yaml or python)",
+)
+def scaffold_object_command(
+    typename: str,
+    path: Path,
+    json_params: Optional[str],
+    scaffold_format: str,
+) -> None:
     key = LibraryObjectKey.from_typename(typename)
     obj = load_library_object(key)
 
@@ -33,4 +43,4 @@ def scaffold_object_command(typename: str, path: Path, json_params: Optional[str
     else:
         scaffold_params = {}
 
-    scaffold_object(path, obj, typename, scaffold_params)
+    scaffold_object(path, obj, typename, scaffold_params, scaffold_format)
diff --git a/python_modules/libraries/dagster-components/dagster_components/component_scaffolding.py b/python_modules/libraries/dagster-components/dagster_components/component_scaffolding.py
index f999bb0e1b22d..b02cee8db77ab 100644
--- a/python_modules/libraries/dagster-components/dagster_components/component_scaffolding.py
+++ b/python_modules/libraries/dagster-components/dagster_components/component_scaffolding.py
@@ -1,12 +1,14 @@
 from collections.abc import Mapping
 from pathlib import Path
-from typing import Any, Optional
+from typing import Any, Optional, cast
 
 import click
 import yaml
+from dagster_shared import check
 
 from dagster_components.scaffold.scaffold import (
     ScaffolderUnavailableReason,
+    ScaffoldFormatOptions,
     ScaffoldRequest,
     get_scaffolder,
 )
@@ -24,16 +26,25 @@ def scaffold_component(
     request: ScaffoldRequest,
     yaml_attributes: Optional[Mapping[str, Any]] = None,
 ) -> None:
-    with open(request.target_path / "component.yaml", "w") as f:
-        component_data = {"type": request.type_name, "attributes": yaml_attributes or {}}
-        yaml.dump(
-            component_data, f, Dumper=ComponentDumper, sort_keys=False, default_flow_style=False
-        )
-        f.writelines([""])
+    if request.scaffold_format == "yaml":
+        with open(request.target_path / "component.yaml", "w") as f:
+            component_data = {"type": request.type_name, "attributes": yaml_attributes or {}}
+            yaml.dump(
+                component_data, f, Dumper=ComponentDumper, sort_keys=False, default_flow_style=False
+            )
+            f.writelines([""])
+    elif request.scaffold_format == "python":
+        raise NotImplementedError("Python scaffolding not yet implemented.")
+    else:
+        check.assert_never(request.scaffold_format)
 
 
 def scaffold_object(
-    path: Path, obj: object, typename: str, scaffold_params: Mapping[str, Any]
+    path: Path,
+    obj: object,
+    typename: str,
+    scaffold_params: Mapping[str, Any],
+    scaffold_format: str,
 ) -> None:
     from dagster_components.component.component import Component
 
@@ -46,7 +57,19 @@ def scaffold_object(
             f"Object type {typename} does not have a scaffolder. Reason: {scaffolder.message}."
         )
 
-    scaffolder.scaffold(ScaffoldRequest(type_name=typename, target_path=path), scaffold_params)
+    check.invariant(
+        scaffold_format in ["yaml", "python"],
+        f"scaffold must be either 'yaml' or 'python'. Got {scaffold_format}.",
+    )
+
+    scaffolder.scaffold(
+        ScaffoldRequest(
+            type_name=typename,
+            target_path=path,
+            scaffold_format=cast(ScaffoldFormatOptions, scaffold_format),
+        ),
+        scaffold_params,
+    )
 
     if isinstance(obj, type) and issubclass(obj, Component):
         component_yaml_path = path / "component.yaml"
diff --git a/python_modules/libraries/dagster-components/dagster_components/scaffold/scaffold.py b/python_modules/libraries/dagster-components/dagster_components/scaffold/scaffold.py
index 76095fb18d71f..af2be19eecdba 100644
--- a/python_modules/libraries/dagster-components/dagster_components/scaffold/scaffold.py
+++ b/python_modules/libraries/dagster-components/dagster_components/scaffold/scaffold.py
@@ -1,11 +1,12 @@
 from abc import abstractmethod
 from dataclasses import dataclass
 from pathlib import Path
-from typing import Any, Callable, Optional, TypeVar, Union
+from typing import Any, Callable, Literal, Optional, TypeVar, Union
 
 from dagster import _check as check
 from dagster._record import record
 from pydantic import BaseModel
+from typing_extensions import TypeAlias
 
 # Type variable for generic class handling
 T = TypeVar("T")
@@ -72,12 +73,17 @@ class ScaffolderUnavailableReason:
     message: str
 
 
+ScaffoldFormatOptions: TypeAlias = Literal["yaml", "python"]
+
+
 @record
 class ScaffoldRequest:
     # fully qualified class name of the decorated object
     type_name: str
     # target path for the scaffold request. Typically used to construct absolute paths
     target_path: Path
+    # yaml or python
+    scaffold_format: ScaffoldFormatOptions
 
 
 class Scaffolder:
diff --git a/python_modules/libraries/dagster-components/dagster_components_tests/cli_tests/test_commands.py b/python_modules/libraries/dagster-components/dagster_components_tests/cli_tests/test_commands.py
index 18f1a2c6516fb..f8d0dd164007e 100644
--- a/python_modules/libraries/dagster-components/dagster_components_tests/cli_tests/test_commands.py
+++ b/python_modules/libraries/dagster-components/dagster_components_tests/cli_tests/test_commands.py
@@ -229,6 +229,8 @@ def test_scaffold_component_command():
                 "bar/components/qux",
                 "--json-params",
                 '{"asset_key": "my_asset", "filename": "my_asset.py"}',
+                "--scaffold-format",
+                "yaml",
             ],
         )
         assert_runner_result(result)
diff --git a/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_sling_integration_test.py b/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_sling_integration_test.py
index c18674a89e77f..fd4b9a69b84bc 100644
--- a/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_sling_integration_test.py
+++ b/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_sling_integration_test.py
@@ -323,6 +323,8 @@ def test_scaffold_sling():
                 "object",
                 "dagster_components.dagster_sling.SlingReplicationCollectionComponent",
                 "bar/components/qux",
+                "--scaffold-format",
+                "yaml",
             ],
         )
         assert result.exit_code == 0
diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/scaffold.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/scaffold.py
index c3e14d9a91083..b3c8f81067ead 100644
--- a/python_modules/libraries/dagster-dg/dagster_dg/cli/scaffold.py
+++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/scaffold.py
@@ -1,10 +1,11 @@
 from collections.abc import Mapping
 from copy import copy
 from pathlib import Path
-from typing import Any, Optional
+from typing import Any, Optional, cast
 
 import click
 from click.core import ParameterSource
+from dagster_shared import check
 from dagster_shared.serdes.objects import LibraryObjectKey, LibraryObjectSnap
 from typer.rich_utils import rich_format_help
 
@@ -26,6 +27,7 @@
 )
 from dagster_dg.context import DgContext
 from dagster_dg.scaffold import (
+    ScaffoldFormatOptions,
     scaffold_component_type,
     scaffold_library_object,
     scaffold_project,
@@ -283,6 +285,7 @@ def _core_scaffold(
     instance_name: str,
     key_value_params,
     json_params,
+    scaffold_format: ScaffoldFormatOptions,
 ) -> None:
     dg_context = DgContext.for_project_environment(Path.cwd(), cli_config)
     registry = RemoteLibraryObjectRegistry.from_dg_context(dg_context)
@@ -316,6 +319,7 @@ def _core_scaffold(
         object_key.to_typename(),
         scaffold_params,
         dg_context,
+        scaffold_format,
     )
 
 
@@ -335,12 +339,19 @@ def _create_scaffold_subcommand(key: LibraryObjectKey, obj: LibraryObjectSnap) -
         help="JSON string of component parameters.",
         callback=parse_json_option,
     )
+    @click.option(
+        "--format",
+        type=click.Choice(["yaml", "python"], case_sensitive=False),
+        default="yaml",
+        help="Format of the component configuration (yaml or python)",
+    )
     @click.pass_context
     @cli_telemetry_wrapper
     def scaffold_command(
         cli_context: click.Context,
         instance_name: str,
         json_params: Mapping[str, Any],
+        format: str,  # noqa: A002 "format" name required for click magic
         **key_value_params: Any,
     ) -> None:
         f"""Scaffold a {key.name} object.
@@ -360,8 +371,20 @@ def scaffold_command(
 
         It is an error to pass both --json-params and key-value pairs as options.
         """
+        check.invariant(
+            format in ["yaml", "python"],
+            "format must be either 'yaml' or 'python'",
+        )
         cli_config = get_config_from_cli_context(cli_context)
-        _core_scaffold(cli_context, cli_config, key, instance_name, key_value_params, json_params)
+        _core_scaffold(
+            cli_context,
+            cli_config,
+            key,
+            instance_name,
+            key_value_params,
+            json_params,
+            cast(ScaffoldFormatOptions, format),
+        )
 
     # If there are defined scaffold params, add them to the command
     if obj.scaffolder_schema:
diff --git a/python_modules/libraries/dagster-dg/dagster_dg/scaffold.py b/python_modules/libraries/dagster-dg/dagster_dg/scaffold.py
index 312f7dbae75b0..634a2f24c93e1 100644
--- a/python_modules/libraries/dagster-dg/dagster_dg/scaffold.py
+++ b/python_modules/libraries/dagster-dg/dagster_dg/scaffold.py
@@ -2,11 +2,12 @@
 import os
 from collections.abc import Mapping
 from pathlib import Path
-from typing import Any, Optional
+from typing import Any, Literal, Optional
 
 import click
 import tomlkit
 import tomlkit.items
+from typing_extensions import TypeAlias
 
 from dagster_dg.component import RemoteLibraryObjectRegistry
 from dagster_dg.config import (
@@ -25,6 +26,7 @@
     set_toml_node,
 )
 
+ScaffoldFormatOptions: TypeAlias = Literal["yaml", "python"]
 # ########################
 # ##### WORKSPACE
 # ########################
@@ -256,7 +258,11 @@ def scaffold_component_type(dg_context: DgContext, class_name: str, module_name:
 
 
 def scaffold_library_object(
-    path: Path, typename: str, scaffold_params: Optional[Mapping[str, Any]], dg_context: "DgContext"
+    path: Path,
+    typename: str,
+    scaffold_params: Optional[Mapping[str, Any]],
+    dg_context: "DgContext",
+    scaffold_format: ScaffoldFormatOptions,
 ) -> None:
     scaffold_command = [
         "scaffold",
@@ -264,5 +270,6 @@ def scaffold_library_object(
         typename,
         str(path),
         *(["--json-params", json.dumps(scaffold_params)] if scaffold_params else []),
+        *(["--scaffold-format", scaffold_format]),
     ]
     dg_context.external_components_command(scaffold_command)
diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_custom_help_format.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_custom_help_format.py
index ca1f4b05f8f56..cb35e90ff299c 100644
--- a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_custom_help_format.py
+++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_custom_help_format.py
@@ -189,21 +189,22 @@ def test_dynamic_subcommand_help_message():
         assert match_terminal_box_output(
             output.strip(),
             textwrap.dedent("""
-                 Usage: dg scaffold [GLOBAL OPTIONS] dagster_test.components.SimplePipesScriptComponent [OPTIONS] INSTANCE_NAME 
-
-                ╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
-                │ *    instance_name      TEXT  [required]                                                                             │
-                ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
-                ╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
-                │ --json-params          TEXT  JSON string of component parameters.                                                    │
-                │ --asset-key            TEXT  asset_key                                                                               │
-                │ --filename             TEXT  filename                                                                                │
-                │ --help         -h            Show this message and exit.                                                             │
-                ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
-                ╭─ Global options ─────────────────────────────────────────────────────────────────────────────────────────────────────╮
-                │ --cache-dir            TEXT  Specify a directory to use for the cache.                                               │
-                │ --disable-cache              Disable the cache..                                                                     │
-                │ --verbose                    Enable verbose output for debugging.                                                    │
-                ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
-        """).strip(),
+Usage: dg scaffold [GLOBAL OPTIONS] dagster_test.components.SimplePipesScriptComponent [OPTIONS] INSTANCE_NAME
+
+╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ *    instance_name      TEXT  [required]                                                                             │
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ --json-params          TEXT           JSON string of component parameters.                                           │
+│ --format               [yaml|python]  Format of the component configuration (yaml or python)                         │
+│ --asset-key            TEXT           asset_key                                                                      │
+│ --filename             TEXT           filename                                                                       │
+│ --help         -h                     Show this message and exit.                                                    │
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─ Global options ─────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ --cache-dir            TEXT  Specify a directory to use for the cache.                                               │
+│ --disable-cache              Disable the cache..                                                                     │
+│ --verbose                    Enable verbose output for debugging.                                                    │
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+                            """).strip(),
         )


Reviews:
user: login: graphite-app[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T15:40:29Z
user: login: OwenKephart
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T17:27:06Z
user: login: graphite-app[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T18:29:17Z

Review comments:
diff_hunk: @@ -19,7 +19,18 @@ def scaffold_cli() -> None:
 @click.argument("typename", type=str)
 @click.argument("path", type=Path)
 @click.option("--json-params", type=str, default=None)
-def scaffold_object_command(typename: str, path: Path, json_params: Optional[str]) -> None:
+@click.option("--scaffold-format")
path: python_modules/libraries/dagster-components/dagster_components/cli/scaffold.py
user: login: graphite-app[bot]
body: There's a duplicate `--scaffold-format` option declaration on line 22. This will cause a Click error when the command is run. The complete option definition already exists in lines 23-27, so this first declaration should be removed to ensure the CLI works correctly.

*Spotted by [Diamond](https://app.graphite.dev/diamond/?org=dagster-io&ref=ai-review-comment)*<i class='graphite__hidden'><br /><br />Is this helpful? React 👍 or 👎 to let us know.</i>
created_at: 2025-03-28T15:40:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -189,21 +189,22 @@ def test_dynamic_subcommand_help_message():
         assert match_terminal_box_output(
             output.strip(),
             textwrap.dedent("""
-                 Usage: dg scaffold [GLOBAL OPTIONS] dagster_test.components.SimplePipesScriptComponent [OPTIONS] INSTANCE_NAME 
-
-                ╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
-                │ *    instance_name      TEXT  [required]                                                                             │
-                ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
-                ╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
-                │ --json-params          TEXT  JSON string of component parameters.                                                    │
-                │ --asset-key            TEXT  asset_key                                                                               │
-                │ --filename             TEXT  filename                                                                                │
-                │ --help         -h            Show this message and exit.                                                             │
-                ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
-                ╭─ Global options ─────────────────────────────────────────────────────────────────────────────────────────────────────╮
-                │ --cache-dir            TEXT  Specify a directory to use for the cache.                                               │
-                │ --disable-cache              Disable the cache..                                                                     │
-                │ --verbose                    Enable verbose output for debugging.                                                    │
-                ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
-        """).strip(),
+Usage: dg scaffold [GLOBAL OPTIONS] dagster_test.components.SimplePipesScriptComponent [OPTIONS] INSTANCE_NAME
+
+╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ *    instance_name      TEXT  [required]                                                                             │
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ --json-params          TEXT           JSON string of component parameters.                                           │
+│ --format               [yaml|python]  Format of the component configuration (yaml or python)                         │
+│ --asset-key            TEXT           asset_key                                                                      │
+│ --filename             TEXT           filename                                                                       │
+│ --help         -h                     Show this message and exit.                                                    │
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─ Global options ─────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ --cache-dir            TEXT  Specify a directory to use for the cache.                                               │
+│ --disable-cache              Disable the cache..                                                                     │
+│ --verbose                    Enable verbose output for debugging.                                                    │
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+                            """).strip(),
path: python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_custom_help_format.py
user: login: graphite-app[bot]
body: The indentation in the updated test output doesn't match the original format. The original test had leading spaces at the beginning of each line, but these have been removed in the updated version. This will likely cause the test to fail since the string comparison expects exact matching. Please restore the leading spaces to maintain the same indentation pattern as the original test output.
```suggestion
    Usage: dg scaffold [GLOBAL OPTIONS] dagster_test.components.SimplePipesScriptComponent [OPTIONS] INSTANCE_NAME

    ╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
    │ *    instance_name      TEXT  [required]                                                                             │
    ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
    ╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
    │ --json-params          TEXT           JSON string of component parameters.                                           │
    │ --format               [yaml|python]  Format of the component configuration (yaml or python)                         │
    │ --asset-key            TEXT           asset_key                                                                      │
    │ --filename             TEXT           filename                                                                       │
    │ --help         -h                     Show this message and exit.                                                    │
    ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
    ╭─ Global options ─────────────────────────────────────────────────────────────────────────────────────────────────────╮
    │ --cache-dir            TEXT  Specify a directory to use for the cache.                                               │
    │ --disable-cache              Disable the cache..                                                                     │
    │ --verbose                    Enable verbose output for debugging.                                                    │
    ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
                            """).strip(),
```
  

*Spotted by [Diamond](https://app.graphite.dev/diamond/?org=dagster-io&ref=ai-review-comment)*<i class='graphite__hidden'><br /><br />Is this helpful? React 👍 or 👎 to let us know.</i>
created_at: 2025-03-28T18:29:15Z
author_association: CONTRIBUTOR

PR comments:
user: login: schrockn
created_at: 2025-03-28T14:54:36Z
body: * **#28848** <a href="https://app.graphite.dev/github/pr/dagster-io/dagster/28848?utm_source=stack-comment-icon" target="_blank"><img src="https://static.graphite.dev/graphite-32x32-black.png" alt="Graphite" width="10px" height="10px"/></a>
* **#28845** <a href="https://app.graphite.dev/github/pr/dagster-io/dagster/28845?utm_source=stack-comment-icon" target="_blank"><img src="https://static.graphite.dev/graphite-32x32-black.png" alt="Graphite" width="10px" height="10px"/></a> 👈 <a href="https://app.graphite.dev/github/pr/dagster-io/dagster/28845?utm_source=stack-comment-view-in-graphite" target="_blank">(View in Graphite)</a>
* **#28843** <a href="https://app.graphite.dev/github/pr/dagster-io/dagster/28843?utm_source=stack-comment-icon" target="_blank"><img src="https://static.graphite.dev/graphite-32x32-black.png" alt="Graphite" width="10px" height="10px"/></a>
* `master`


<h2></h2>

This stack of pull requests is managed by <a href="https://graphite.dev?utm-source=stack-comment"><b>Graphite</b></a>. Learn more about <a href="https://stacking.dev/?utm_source=stack-comment">stacking</a>.
<!-- Current dependencies on/for this PR: -->
author_association: MEMBER
user: login: schrockn
created_at: 2025-03-28T18:26:27Z
body: ### Merge activity

* **Mar 28, 2:26 PM EDT**: A user started a stack merge that includes this pull request via [Graphite](https://app.graphite.dev/github/pr/dagster-io/dagster/28845).
* **Mar 28, 2:27 PM EDT**: [Graphite](https://app.graphite.dev/github/pr/dagster-io/dagster/28845) rebased this pull request as part of a merge.
* **Mar 28, 2:29 PM EDT**: [Graphite](https://app.graphite.dev/github/pr/dagster-io/dagster/28845) rebased this pull request as part of a merge.
* **Mar 28, 2:30 PM EDT**: [Graphite](https://app.graphite.dev/github/pr/dagster-io/dagster/28845) rebased this pull request as part of a merge.
* **Mar 28, 2:31 PM EDT**: A user merged this pull request with [Graphite](https://app.graphite.dev/github/pr/dagster-io/dagster/28845).

author_association: MEMBER