ashb commented on code in PR #74084:
URL: https://github.com/apache/airflow/pull/74084#discussion_r4237929211


##########
task-sdk/src/airflow/sdk/importers/yaml_importer/models.py:
##########
@@ -0,0 +1,409 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+"""
+Pydantic models for the YAML/JSON DAG format.
+
+These are the single source of truth for the format; they validate an authored
+document (rich Pydantic errors) and back the published JSON Schema. Only the
+format skeleton and value grammar only is described; operator ``with:`` args,
+Dag- and task-level attributes pass through untyped because the Python
+constructors validate those at import time.
+"""
+
+from __future__ import annotations
+
+import collections
+import itertools
+from typing import TYPE_CHECKING, Annotated, Any, ClassVar
+
+from pydantic import (
+    AliasChoices,
+    BaseModel,
+    ConfigDict,
+    Discriminator,
+    Field,
+    RootModel,
+    Tag,
+    model_validator,
+)
+
+if TYPE_CHECKING:
+    from pydantic import GetJsonSchemaHandler
+    from pydantic.json_schema import JsonSchemaValue
+    from pydantic_core import CoreSchema
+
+XCOM_KEYS = ("$x", "$xcom")
+TEMPLATE_KEYS = ("$t", "$template")
+CONST_KEY = "$const"
+
+# Keys deferred to a later edition...
+DAG_CALLBACK_KEYS = {"on_success_callback", "on_failure_callback"}
+TASK_CALLBACK_KEYS = {
+    "on_success_callback",
+    "on_failure_callback",
+    "on_retry_callback",
+    "on_execute_callback",
+    "on_skipped_callback",
+}
+TASK_ASSET_IO_KEYS = {"inlets", "outlets"}
+
+
+class XComTarget(BaseModel):
+    """The object form of an XCom reference."""
+
+    task: str
+    key: str | None = None
+
+    model_config = ConfigDict(extra="forbid")
+
+
+class _MarkerRef(BaseModel):
+    """Base for a reserved ``$``-marker object."""
+
+    model_config = ConfigDict(extra="forbid")
+
+    _marker_keys: ClassVar[tuple[str, ...]]
+
+    @classmethod
+    def __get_pydantic_json_schema__(
+        cls, core_schema: CoreSchema, handler: GetJsonSchemaHandler
+    ) -> JsonSchemaValue:
+        # Emit the marker as a single key in every accepted spelling, nothing 
else.
+        schema = handler(core_schema)
+        (value_schema,) = schema.get("properties", {}).values()
+        schema["properties"] = {key: value_schema for key in cls._marker_keys}
+        schema.pop("required", None)
+        schema["oneOf"] = [{"required": [key]} for key in cls._marker_keys]
+        schema["additionalProperties"] = False
+        return schema
+
+
+class XComRef(_MarkerRef):
+    """An upstream task's XCom output."""
+
+    _marker_keys = XCOM_KEYS
+
+    target: str | XComTarget = Field(
+        serialization_alias="$x",
+        validation_alias=AliasChoices(*XCOM_KEYS),
+    )
+
+
+class TemplateRef(_MarkerRef):
+    """A Jinja template."""
+
+    _marker_keys = TEMPLATE_KEYS
+
+    source: str = Field(serialization_alias="$t", 
validation_alias=AliasChoices(*TEMPLATE_KEYS))
+
+
+class ConstRef(_MarkerRef):
+    """Force a literal; the value is taken verbatim."""
+
+    _marker_keys = (CONST_KEY,)
+
+    value: Any = Field(serialization_alias="$const", 
validation_alias=AliasChoices(CONST_KEY))
+
+
+def _value_discriminator(v: Any) -> str:
+    """
+    Route a raw value to a marker branch, or to ``literal``.
+
+    The prefix ``$`` is reserved to express Airflow constructs. To prevent
+    typos, any unknown ``$``-prefixed strings are routed here and rejected.
+
+    If such a key is needed, it can be wrapped in ``$const``, which would
+    avoid this discrimator (only used by :class:`_Literal`).
+    """
+    if isinstance(v, dict) and len(v) == 1:
+        (key,) = v
+        if key in XCOM_KEYS:
+            return "xcom"
+        if key in TEMPLATE_KEYS:
+            return "template"
+        if key == CONST_KEY:
+            return "const"
+    if isinstance(v, XComRef):
+        return "xcom"
+    if isinstance(v, TemplateRef):
+        return "template"
+    if isinstance(v, ConstRef):
+        return "const"
+    return "literal"
+
+
+class _Literal(RootModel):
+    """
+    A literal value.
+
+    Containers are validated recursively so nested markers resolve; scalars 
pass
+    through. A ``$``-prefixed key here is a misused marker, so it is rejected.
+    """
+
+    root: dict[str, Value] | list[Value] | str | int | float | bool | None

Review Comment:
   Oh, no it turns out it is part of the spec. TIL.



-- 
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]

Reply via email to