This is an automated email from the ASF dual-hosted git repository.
amoghdesai 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 0923f64f56d Expose macros module in `airflow.sdk` public API (#60808)
0923f64f56d is described below
commit 0923f64f56db4b7818a88ec3d7cbda2c8038813f
Author: Amogh Desai <[email protected]>
AuthorDate: Wed Jan 21 12:28:07 2026 +0530
Expose macros module in `airflow.sdk` public API (#60808)
---
task-sdk/docs/api.rst | 17 +++++++++++++++++
task-sdk/src/airflow/sdk/__init__.py | 3 +++
task-sdk/src/airflow/sdk/__init__.pyi | 2 ++
task-sdk/src/airflow/sdk/execution_time/__init__.py | 3 +++
task-sdk/tests/task_sdk/docs/test_docs_inventory.py | 2 +-
5 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/task-sdk/docs/api.rst b/task-sdk/docs/api.rst
index 66fe1637486..69c0f6f136e 100644
--- a/task-sdk/docs/api.rst
+++ b/task-sdk/docs/api.rst
@@ -34,6 +34,23 @@ Configuration
The ``conf`` object is available as part of the Task SDK. It provides an
interface to the
configurations, allowing you to read and interact with Airflow configuration
values.
+
+Macros
+------
+
+The ``macros`` module is available as part of the Task SDK. It provides
builtin utility functions
+for date manipulation and other common operations in Jinja templates and task
code.
+
+Available functions include:
+
+- ``ds_add(ds, days)`` - Add or subtract days from a date string
+- ``ds_format(ds, input_format, output_format)`` - Format datetime strings
+- ``ds_format_locale(ds, input_format, output_format, locale)`` - Format
datetime strings with locale support
+- ``datetime_diff_for_humans(dt, since)`` - Human-readable datetime differences
+
+The module also provides direct access to commonly used standard library
modules:
+``json``, ``time``, ``uuid``, ``dateutil``, and ``random``.
+
Decorators
----------
.. autoapifunction:: airflow.sdk.dag
diff --git a/task-sdk/src/airflow/sdk/__init__.py
b/task-sdk/src/airflow/sdk/__init__.py
index 034a6379430..9970a081ab1 100644
--- a/task-sdk/src/airflow/sdk/__init__.py
+++ b/task-sdk/src/airflow/sdk/__init__.py
@@ -65,6 +65,7 @@ __all__ = [
"get_current_context",
"get_parsing_context",
"literal",
+ "macros",
"setup",
"task",
"task_group",
@@ -112,6 +113,7 @@ if TYPE_CHECKING:
)
from airflow.sdk.definitions.variable import Variable
from airflow.sdk.definitions.xcom_arg import XComArg
+ from airflow.sdk.execution_time import macros
from airflow.sdk.io.path import ObjectStoragePath
from airflow.sdk.observability.trace import Trace
@@ -164,6 +166,7 @@ __lazy_imports: dict[str, str] = {
"get_current_context": ".definitions.context",
"get_parsing_context": ".definitions.context",
"literal": ".definitions.template",
+ "macros": ".execution_time",
"setup": ".definitions.decorators",
"task": ".definitions.decorators",
"task_group": ".definitions.decorators",
diff --git a/task-sdk/src/airflow/sdk/__init__.pyi
b/task-sdk/src/airflow/sdk/__init__.pyi
index b035f49226c..1008c213627 100644
--- a/task-sdk/src/airflow/sdk/__init__.pyi
+++ b/task-sdk/src/airflow/sdk/__init__.pyi
@@ -71,6 +71,7 @@ from airflow.sdk.definitions.timetables.trigger import (
)
from airflow.sdk.definitions.variable import Variable as Variable
from airflow.sdk.definitions.xcom_arg import XComArg as XComArg
+from airflow.sdk.execution_time import macros as macros
from airflow.sdk.execution_time.cache import SecretCache as SecretCache
from airflow.sdk.io.path import ObjectStoragePath as ObjectStoragePath
@@ -121,6 +122,7 @@ __all__ = [
"get_current_context",
"get_parsing_context",
"literal",
+ "macros",
"setup",
"task",
"task_group",
diff --git a/task-sdk/src/airflow/sdk/execution_time/__init__.py
b/task-sdk/src/airflow/sdk/execution_time/__init__.py
index 217e5db9607..e5a94d79265 100644
--- a/task-sdk/src/airflow/sdk/execution_time/__init__.py
+++ b/task-sdk/src/airflow/sdk/execution_time/__init__.py
@@ -15,3 +15,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
+from __future__ import annotations
+
+from airflow.sdk.execution_time import macros as macros
diff --git a/task-sdk/tests/task_sdk/docs/test_docs_inventory.py
b/task-sdk/tests/task_sdk/docs/test_docs_inventory.py
index a74ed11efbc..9bac05503b4 100644
--- a/task-sdk/tests/task_sdk/docs/test_docs_inventory.py
+++ b/task-sdk/tests/task_sdk/docs/test_docs_inventory.py
@@ -77,7 +77,7 @@ def test_docs_inventory_matches_public_api(tmp_path):
extras = {"AirflowParsingContext"}
# we do not want to document the class for `conf` but a description is
present in the docs
- excluded_from_docs = {"conf"}
+ excluded_from_docs = {"conf", "macros"}
missing = (public - documented) - excluded_from_docs
assert not missing, f"Public API items missing in docs: {missing}"
unexpected = (documented - public) - extras