This is an automated email from the ASF dual-hosted git repository.
jscheffl pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new a9764afd3fc Docs: add doc_md and task docstrings to measurement
correction example Dags (#66707)
a9764afd3fc is described below
commit a9764afd3fce151f94bf9a29f59e5c494adc2dc2
Author: André Ahlert <[email protected]>
AuthorDate: Mon May 11 17:22:10 2026 -0300
Docs: add doc_md and task docstrings to measurement correction example Dags
(#66707)
Follow-up to #66257 addressing review feedback from @jscheffl:
- Expand module docstrings on both example Dags with storyline, scope and
no-external-dependencies notes.
- Add a Dag-level doc_md so the storyline shows up in the UI Dag details
page.
- Add task-level docstrings explaining what each step does and how it
would map to a production pipeline.
- Reference both example Dags from the Example Dag Review Checklist as
canonical templates for new tutorial-style examples.
Signed-off-by: André Ahlert <[email protected]>
---
.../28_example_dag_review_checklist.rst | 17 +++++
.../example_measurement_correction_decorator.py | 77 ++++++++++++++++++----
.../example_measurement_correction_operator.py | 63 ++++++++++++++++--
3 files changed, 137 insertions(+), 20 deletions(-)
diff --git a/contributing-docs/28_example_dag_review_checklist.rst
b/contributing-docs/28_example_dag_review_checklist.rst
index 9647b62d266..b32b6aabf7b 100644
--- a/contributing-docs/28_example_dag_review_checklist.rst
+++ b/contributing-docs/28_example_dag_review_checklist.rst
@@ -94,3 +94,20 @@ Provider examples have slightly different expectations:
- [ ] Provider dependencies are clearly documented in the docstring.
- [ ] Example is not auto-loaded unless intended.
- [ ] Example naming follows provider naming conventions.
+
+Reference Examples
+------------------
+
+The following example Dags are kept aligned with this checklist and are good
+templates for new tutorial-style examples. Both implement the same
+"measurement correction" storyline so the TaskFlow and ``PythonOperator``
+styles can be compared side by side:
+
+- `example_measurement_correction_decorator.py
+
<https://github.com/apache/airflow/blob/main/providers/standard/src/airflow/providers/standard/example_dags/example_measurement_correction_decorator.py>`_
— TaskFlow version.
+- `example_measurement_correction_operator.py
+
<https://github.com/apache/airflow/blob/main/providers/standard/src/airflow/providers/standard/example_dags/example_measurement_correction_operator.py>`_
— classic ``PythonOperator`` version.
+
+When introducing a new tutorial-style example, prefer copying the shape of
+these two files (module docstring, ``doc_md``, per-task docstrings, no
+external dependencies) rather than starting from scratch.
diff --git
a/providers/standard/src/airflow/providers/standard/example_dags/example_measurement_correction_decorator.py
b/providers/standard/src/airflow/providers/standard/example_dags/example_measurement_correction_decorator.py
index a7a5f177ac0..b41f49ba676 100644
---
a/providers/standard/src/airflow/providers/standard/example_dags/example_measurement_correction_decorator.py
+++
b/providers/standard/src/airflow/providers/standard/example_dags/example_measurement_correction_decorator.py
@@ -14,8 +14,23 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
+"""
+Tutorial example Dag: measurement correction storyline (TaskFlow).
-"""Example Dag demonstrating a simple measurement correction workflow"""
+This Dag is part of the "Examples Refurbish" storyline and is meant to be a
+short, didactic walkthrough of a typical scientific or industrial data
+pipeline. It demonstrates the TaskFlow API on a self-contained workflow that:
+
+1. reads a raw measurement,
+2. validates it,
+3. applies a correction factor,
+4. stores the corrected result.
+
+The Dag has no external dependencies (no connections, no datasets, no hooks),
+so it parses and runs out of the box. Pair it with
+``example_measurement_correction_operator.py`` to compare TaskFlow and the
+classic ``PythonOperator`` style on the exact same storyline.
+"""
from __future__ import annotations
@@ -23,6 +38,27 @@ import pendulum
from airflow.sdk import dag, task
+DAG_DOC_MD = """
+### Measurement correction (TaskFlow)
+
+Tutorial Dag showing a minimal "read, validate, correct, store" measurement
+pipeline implemented with the TaskFlow API.
+
+**Storyline**
+
+1. `read_measurement` produces a raw value coming from a fictional sensor.
+2. `validate_measurement` rejects negative values.
+3. `apply_correction` multiplies the value by a calibration factor.
+4. `store_result` logs the corrected value (the real Dag would persist it).
+
+**When to use this example**
+
+- Learning the TaskFlow API on a single, linear pipeline.
+- As a reference shape for new "tutorial" example Dags following the
+ [example Dag review checklist](
+
https://github.com/apache/airflow/blob/main/contributing-docs/28_example_dag_review_checklist.rst).
+"""
+
# [START example_measurement_correction_decorator]
@dag(
@@ -31,37 +67,52 @@ from airflow.sdk import dag, task
schedule=None,
catchup=False,
tags=["example"],
+ doc_md=DAG_DOC_MD,
)
def measurement_correction_decorator():
- """
- A tutorial Dag showing how to:
- 1. Read a raw measurement
- 2. Validate the measurement
- 3. Apply a correction factor
- 4. Log the corrected result
- """
-
- # Task 1: Read a raw measurement
+ """Tutorial Dag: read, validate, correct, and store a measurement."""
+
@task
def read_measurement() -> int:
+ """Return the raw measurement coming from the source system.
+
+ In a real pipeline this would fetch the value from a sensor, an
+ external API, or an upstream dataset. For the tutorial it returns a
+ constant so the Dag is fully self-contained.
+ """
return 100
- # Task 2: Validate the measurement
@task
def validate_measurement(value: int) -> int:
+ """Reject obviously invalid measurements.
+
+ Raises ``ValueError`` when ``value`` is negative, so the failure is
+ visible as a failed task in the UI instead of silently corrupting
+ downstream data.
+ """
if value < 0:
raise ValueError("Measurement must be positive")
return value
- # Task 3: Apply a correction factor
@task
def apply_correction(value: int) -> float:
+ """Apply the calibration factor to a validated measurement.
+
+ The factor (``1.1``) is hard-coded here for brevity; a real pipeline
+ would read it from a Variable, a Connection extra, or a config file.
+ """
correction_factor = 1.1
return value * correction_factor
- # Task 4: Log the final corrected result
@task
def store_result(value: float) -> None:
+ """Persist the corrected measurement.
+
+ The tutorial implementation logs the value via ``print`` so the
+ result is visible in the task logs. A production Dag would write it
+ to a database, an object store, or publish it to a downstream
+ system.
+ """
print(f"Corrected measurement: {value}")
raw_value = read_measurement()
diff --git
a/providers/standard/src/airflow/providers/standard/example_dags/example_measurement_correction_operator.py
b/providers/standard/src/airflow/providers/standard/example_dags/example_measurement_correction_operator.py
index 0bcbf8154ba..43e7faa29d6 100644
---
a/providers/standard/src/airflow/providers/standard/example_dags/example_measurement_correction_operator.py
+++
b/providers/standard/src/airflow/providers/standard/example_dags/example_measurement_correction_operator.py
@@ -15,8 +15,16 @@
# specific language governing permissions and limitations
# under the License.
"""
-Example Dag demonstrating a simple measurement correction workflow
-using operator PythonOperator tasks.
+Tutorial example Dag: measurement correction storyline (PythonOperator).
+
+Classic, ``PythonOperator`` based counterpart of
+``example_measurement_correction_decorator.py``. It runs the same
+"read, validate, correct, store" pipeline so that learners can compare the
+TaskFlow API and the operator-based style on identical business logic.
+
+The Dag has no external dependencies (no connections, no datasets, no hooks),
+so it parses and runs out of the box and is suitable as a tutorial or as a
+documentation snippet.
"""
from __future__ import annotations
@@ -26,28 +34,69 @@ import pendulum
from airflow.providers.standard.operators.python import PythonOperator
from airflow.sdk import DAG
+DAG_DOC_MD = """
+### Measurement correction (PythonOperator)
+
+Tutorial Dag showing a minimal "read, validate, correct, store" measurement
+pipeline implemented with classic ``PythonOperator`` tasks and XCom for
+inter-task communication.
+
+**Storyline**
+
+1. `read_measurement` returns a raw value.
+2. `validate_measurement` pulls it from XCom and rejects negative values.
+3. `apply_correction` multiplies it by a calibration factor.
+4. `store_result` logs the corrected value.
+
+**When to use this example**
+
+- Comparing the TaskFlow API with the classic operator style on the same
+ storyline (see ``example_measurement_correction_decorator.py``).
+- As a reference shape for new "tutorial" example Dags following the
+ [example Dag review checklist](
+
https://github.com/apache/airflow/blob/main/contributing-docs/28_example_dag_review_checklist.rst).
+"""
+
-# Task 1: Return a raw measurement value
def read_measurement(**context):
+ """Return the raw measurement value pushed to XCom.
+
+ The returned value becomes the task's XCom payload so the downstream
+ tasks can pull it with ``ti.xcom_pull``.
+ """
return 100
-# Task 2: Validate the measurement value
def validate_measurement(**context):
+ """Validate the upstream measurement pulled from XCom.
+
+ Raises ``ValueError`` when the value is negative so the failure is
+ visible as a failed task in the UI instead of silently corrupting
+ downstream data.
+ """
value = context["ti"].xcom_pull(task_ids="read_measurement")
if value < 0:
raise ValueError("Measurement must be positive")
return value
-# Task 3: Apply correction factor
def apply_correction(**context):
+ """Apply the calibration factor to a validated measurement.
+
+ The factor (``1.1``) is hard-coded for brevity; a production pipeline
+ would source it from a Variable, a Connection extra, or a config file.
+ """
value = context["ti"].xcom_pull(task_ids="validate_measurement")
return value * 1.1
-# Task 4: Log the corrected result
def store_result(**context):
+ """Persist the corrected measurement.
+
+ The tutorial implementation logs the value via ``print`` so the result
+ is visible in the task logs. A production Dag would write it to a
+ database, an object store, or publish it to a downstream system.
+ """
value = context["ti"].xcom_pull(task_ids="apply_correction")
print(f"Corrected measurement: {value}")
@@ -59,6 +108,7 @@ with DAG(
schedule=None,
catchup=False,
tags=["example"],
+ doc_md=DAG_DOC_MD,
) as dag:
read = PythonOperator(
task_id="read_measurement",
@@ -80,6 +130,5 @@ with DAG(
python_callable=store_result,
)
- # Define execution order
read >> validate >> correct >> store
# [END example_measurement_correction_operator]