[airflow] Implement airflow-xcom-pull-in-template-string (AIR004)#23583
[airflow] Implement airflow-xcom-pull-in-template-string (AIR004)#23583Dev-iL wants to merge 1 commit intoastral-sh:mainfrom
Conversation
|
| code | total | + violation | - violation | + fix | - fix |
|---|---|---|---|---|---|
| AIR004 | 18 | 18 | 0 | 0 | 0 |
c0c2205 to
fb18572
Compare
|
cc @sjyangkevin for review? |
| #[cfg(test)] | ||
| mod tests { | ||
| use super::parse_xcom_pull_template; | ||
|
|
||
| #[test] | ||
| fn test_basic_ti_xcom_pull() { | ||
| assert_eq!( | ||
| parse_xcom_pull_template("{{ ti.xcom_pull(task_ids='my_task') }}"), | ||
| Some("my_task".to_string()) | ||
| ); | ||
| } |
There was a problem hiding this comment.
Just curious about what are these tests 🤔
There was a problem hiding this comment.
Claude can explain this best:
This is a unit test for the
parse_xcom_pull_templatehelper function. It verifies the happy path: given a standard Jinja template string{{ ti.xcom_pull(task_ids='my_task') }}, the parser correctly extracts and returns the task ID"my_task".This matters because
parse_xcom_pull_templateis a pure string-parsing function (no AST, no checker context), so it can be tested in isolation without spinning up the full linter infrastructure. The broader test module (lines 172–268) covers the full matrix of the parser's behavior:
- Positive cases: both receiver names (
tivstask_instance), positional vs keyword argument,task_idvstask_ids, single vs double quotes, varying whitespace.- Negative cases: mixed content around the template, additional keyword arguments (
key=...), empty task IDs, non-template strings, list-valuedtask_ids.Together they ensure the hand-rolled parser is robust without needing snapshot-based integration tests for every string variation. The integration-level behavior (detecting operator calls, emitting diagnostics, generating fixes) is covered separately by the snapshot fixtures in
crates/ruff_linter/resources/test/fixtures/airflow/.
would be great to also have @Lee-W to have a look when he is available. |
fb18572 to
438534f
Compare
438534f to
ca33d94
Compare
Summary
Implements rule
AIR004(airflow-xcom-pull-in-template-string) that detects Airflow operator/sensor keyword arguments using a Jinja template string containing a singlexcom_pullcall (e.g.,"{{ ti.xcom_pull(task_ids='some_task') }}") and suggests replacing it with the.outputattribute on the task object (e.g.,some_task.output).Using
.outputinstead ofxcom_pulltemplate strings:@task-decorated functions)What the rule flags
Suggested fix
Template patterns detected
{{ ti.xcom_pull(task_ids='...') }}and{{ task_instance.xcom_pull(task_ids='...') }}{{ ti.xcom_pull('...') }}task_id=andtask_ids=keyword formsWhat it allows (no false positives)
"echo {{ ti.xcom_pull(task_ids='task_1') }}""{{ ti.xcom_pull(task_ids='task_1', key='my_key') }}".output:task_1.output"{{ ti.xcom_pull(task_ids=['a', 'b']) }}"DAG(...))Unsafe fix
When the referenced
task_idmatches a variable in scope (either an operator assignment or a@task-decorated function), an unsafe fix is provided that replaces the template string with<variable>.output. When no matching variable is found, the diagnostic is still reported but without an auto-fix.Test Plan
AIR004.pycovering:ti.xcom_pull,task_instance.xcom_pull, positional args, double quotes, no-space braces, singulartask_idkeyword, sensors, provider operators, and@task-decorated function sources.task_idnot visible as a variable in the current scope..output, regular strings, non-string arguments, listtask_ids, and non-operator calls.parse_xcom_pull_templateparser covering all template variants and rejection cases.related: apache/airflow#43176