Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion task-sdk/src/airflow/sdk/bases/decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -528,8 +528,10 @@ def __call__(self, *args: FParams.args, **kwargs: FParams.kwargs) -> XComArg:
op.returns_dag_result = self.returns_dag_result
op_doc_attrs = [op.doc, op.doc_json, op.doc_md, op.doc_rst, op.doc_yaml]
# Set the task's doc_md to the function's docstring if it exists and no other doc* args are set.
# cleandoc strips the leading indentation the docstring inherits from the nested function so it
# renders as Markdown rather than an indented code block.
if self.function.__doc__ and not any(op_doc_attrs):
op.doc_md = self.function.__doc__
op.doc_md = inspect.cleandoc(self.function.__doc__)
return XComArg(op)

def _validate_arg_names(self, func: ValidationSource, kwargs: dict[str, Any]):
Expand Down
12 changes: 12 additions & 0 deletions task-sdk/tests/task_sdk/bases/test_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ def test_get_python_source_strips_decorator_and_comment(self, tmp_path: Path):
ast.parse(cleaned)
assert cleaned.lstrip().splitlines()[0].startswith("def a_task")

def test_docstring_used_as_doc_md_is_dedented(self):
@task
def my_task():
"""Summary line.

Body line indented under the function.
"""

op = my_task().operator

assert op.doc_md == "Summary line.\n\nBody line indented under the function."


class DummyDecoratedOperator(DecoratedOperator):
custom_operator_name = "@task.dummy"
Expand Down