Skip to content

Commit 24d8c66

Browse files
Prevent Dag CLI subcommands from being silently dropped (#72340)
1 parent a32662c commit 24d8c66

2 files changed

Lines changed: 27 additions & 7 deletions

File tree

airflow-core/src/airflow/cli/cli_config.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2348,24 +2348,24 @@ class GroupCommand(NamedTuple):
23482348

23492349
def _remove_dag_id_opt(command: ActionCommand):
23502350
cmd = command._asdict()
2351-
cmd["args"] = (arg for arg in command.args if arg is not ARG_DAG_ID)
2351+
cmd["args"] = tuple(arg for arg in command.args if arg is not ARG_DAG_ID)
23522352
return ActionCommand(**cmd)
23532353

23542354

2355+
# Subcommands ``DAG.cli()`` exposes, via ``get_parser(dag_parser=True)``.
2356+
DAG_CLI_DAGS_SUBCOMMANDS = ("list-runs", "pause", "unpause", "test")
2357+
DAG_CLI_TASKS_SUBCOMMANDS = ("list", "test")
2358+
23552359
dag_cli_commands: list[CLICommand] = [
23562360
GroupCommand(
23572361
name="dags",
23582362
help="Manage DAGs",
2359-
subcommands=[
2360-
_remove_dag_id_opt(sp)
2361-
for sp in DAGS_COMMANDS
2362-
if sp.name in ["backfill", "list-runs", "pause", "unpause", "test"]
2363-
],
2363+
subcommands=[_remove_dag_id_opt(sp) for sp in DAGS_COMMANDS if sp.name in DAG_CLI_DAGS_SUBCOMMANDS],
23642364
),
23652365
GroupCommand(
23662366
name="tasks",
23672367
help="Manage tasks",
2368-
subcommands=[_remove_dag_id_opt(sp) for sp in TASKS_COMMANDS if sp.name in ["list", "test", "run"]],
2368+
subcommands=[_remove_dag_id_opt(sp) for sp in TASKS_COMMANDS if sp.name in DAG_CLI_TASKS_SUBCOMMANDS],
23692369
),
23702370
]
23712371
DAG_CLI_DICT: dict[str, CLICommand] = {sp.name: sp for sp in dag_cli_commands}

airflow-core/tests/unit/cli/test_cli_parser.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,26 @@ def test_dag_cli_should_display_help(self):
496496
with pytest.raises(SystemExit):
497497
parser.parse_args([*cmd_args, "--help"])
498498

499+
@pytest.mark.parametrize(
500+
("selected_names", "source_commands"),
501+
[
502+
pytest.param(cli_config.DAG_CLI_DAGS_SUBCOMMANDS, cli_config.DAGS_COMMANDS, id="dags"),
503+
pytest.param(cli_config.DAG_CLI_TASKS_SUBCOMMANDS, cli_config.TASKS_COMMANDS, id="tasks"),
504+
],
505+
)
506+
def test_dag_cli_subcommands_all_exist(self, selected_names, source_commands):
507+
"""A name that no longer exists is silently dropped, so guard against stale entries."""
508+
assert set(selected_names) <= {command.name for command in source_commands}
509+
510+
def test_dag_cli_parser_keeps_args_when_rebuilt(self):
511+
"""``_remove_dag_id_opt`` must not hand argparse a one-shot generator."""
512+
cli_parser.get_parser.cache_clear()
513+
first = vars(cli_parser.get_parser(dag_parser=True).parse_args(["dags", "pause"]))
514+
cli_parser.get_parser.cache_clear()
515+
second = vars(cli_parser.get_parser(dag_parser=True).parse_args(["dags", "pause"]))
516+
assert "treat_dag_id_as_regex" in first
517+
assert first.keys() == second.keys()
518+
499519
def test_positive_int(self):
500520
assert cli_config.positive_int(allow_zero=True)("1") == 1
501521
assert cli_config.positive_int(allow_zero=True)("0") == 0

0 commit comments

Comments
 (0)