Eason09053360 opened a new pull request, #72810: URL: https://github.com/apache/airflow/pull/72810
Running a Dag file as a script (`python my_dag.py dags test --show-dagrun`) goes through `DAG.cli()`. Its Dag-scoped parser drops the `dag_id` positional and passes the Dag object to the handler instead, so the parsed `Namespace` has no `dag_id` attribute at all. `dag_test` never needed it until it rendered the run: the task instance query read `args.dag_id`, so `--show-dagrun`, `--save-dagrun` and `--imgcat-dagrun` all raised `AttributeError: 'Namespace' object has no attribute 'dag_id'` after the Dag had already run, while the same command without a rendering flag succeeded. The regular `airflow dags test <dag_id> --show-dagrun` path was never affected. ### Fix The query now filters on the resolved Dag's id. On the regular path that is the same string as `args.dag_id` (the Dag was looked up by it), and on the `DAG.cli()` path it is the only id available. That lookup was the single reader of `args.dag_id` after the Dag is resolved, because `dag or get_bagged_dag(...)` short-circuits when a Dag is passed in. ### Testing - New `test_dag_test_show_dag_from_dag_cli` drives `dag_test` the way `DAG.cli()` does (Dag-scoped parser, Dag passed positionally), seeds a Dag run with one task instance via `dag_maker`, and asserts that instance reaches `render_dag`. Without the fix it fails on the same `AttributeError`; with it the whole file passes (107 tests). - `test_dag_test_show_dag` now gives its mocked Dag a real `dag_id`, since a `MagicMock` cannot be bound as a SQL parameter. - Reproduced end to end on a sqlite metadata DB with a one-task Dag in the dags folder: before the fix the `DAG.cli()` invocation exited 1 with the traceback above; after it prints the same DOT graph as `airflow dags test <dag_id> --show-dagrun`. Note for reproduction: the Dag file has to live inside a configured bundle and be serialized first (`airflow dags reserialize`), otherwise `dag.test()` fails earlier on both paths with "Cannot create DagRun ... because the dag is not serialized". Related: #72109 fixed the same `DAG.cli()` dispatch shape for `dags pause` and `dags unpause`. A pre-existing, separate limitation surfaced during review and is out of scope here: `@action_cli` snapshots `dag_id` from the `Namespace` before the handler runs, so audit `Log` rows for any `DAG.cli()` subcommand carry `dag_id=NULL`. The natural place to fix that is `DAG.cli()` itself. --- ##### Was generative AI tooling used to co-author this PR? - [X] Yes — Claude Code (Fable 5.1) Generated-by: Claude Code (Fable 5.1) following [the guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
