The GitHub Actions job "Tests (AMD)" on airflow.git/main has failed. Run started by GitHub user potiuk (triggered by potiuk).
Head commit for run: 3733e62d6a4262a4e4e11759ebc201d25e9a9142 / Anurag Pappula <[email protected]> Type asset_expression in the REST API so the UI does not cast through unknown (#67725) * Type asset_expression in the REST API instead of an untyped dict asset_expression was declared as `dict | None` on the REST API response models, so the OpenAPI generator emitted an opaque `{ [k: string]: unknown }` and the UI hand-maintained an ExpressionType union and cast the value through it with no runtime check. A change to the server shape would not be caught by the TypeScript build. This adds a structured, recursive AssetExpression model in datamodels/common.py: a discriminated union over the five shapes BaseAsset.as_expression() produces (asset, alias, asset_ref, any, all), following the existing Annotated[Union[...], Discriminator] pattern. It is used on every response that serves the field (DAG details, DAGs with latest runs, and both partitioned dag run responses), types the next_run_assets UI endpoint with a NextRunAssetsResponse model, regenerates the OpenAPI spec and the TypeScript client, and removes the now-redundant hand-written union and casts in the UI. The asset leaf carries the optional id that DagModelOperation injects on persistence; id is optional so a row written before id-enrichment, or migrated from the pre-3.0 dataset format, still validates. For expressions produced by current code the emitted JSON is unchanged, so this is not a breaking change for API consumers; only the declared schema becomes precise. The test_get_dags fixtures previously set asset_expression to a simplified `{"any": [{"uri": ...}]}` shape that as_expression() never produces. That was harmless against an untyped dict but the structured model correctly rejects the bare leaf, so the fixtures now use the real `{"any": [{"asset": {...}}]}` shape with each asset's name and group. * Derive ExpressionType from generated types, drop manual aliases ExpressionType is now NonNullable<DAGDetailsResponse["asset_expression"]> instead of a hand-maintained union that could drift from the server shape. Remove AssetSummary and inline its union at the only use site (AssetNode), and drop the explanatory comment. Per review feedback. * Remove unused NextRunEvent type from AssetExpression * Apply ruff-format to partitioned_dag_runs route Wrap the over-length created_at/updated_at ternaries so the ruff-format pre-commit hook passes. No behaviour change. * Degrade legacy asset_expression shapes to null instead of 500ing the API The newly-typed asset_expression field rejects pre-3.0 dataset shapes (a bare uri string, {"any": [<strings>]}, {"alias": "<name>"}) that the 2.x->3.x column rename carried over verbatim, which would surface as an HTTP 500 on the dag-detail, dag-list and next_run_assets endpoints until the dag is re-parsed. MaybeAssetExpression wraps the union with a BeforeValidator that coerces any unrecognized stored shape to null, reproducing the blank render the UI showed while the field was an untyped dict. Adds round-trip and coercion tests. * Log a warning when an unrecognized asset_expression shape is dropped Per review feedback: the tolerant validator silently coerced any unrecognized shape to None, which also masked genuine server/UI shape drift this PR guards against. Emit a warning when a non-None value is dropped so the drift stays observable. Graceful degradation behaviour is unchanged. * Extract response dict into a named variable before model_validate Per review feedback: pull the dict passed to .model_validate() into a model_data local in the UI routes that build responses from a dict, which reads better for the larger payloads. No behaviour change. * Annotate extracted model_data dicts as dict[str, Any] The dict literals were inferred with a narrow value type once pulled into a local, so mypy rejected heterogeneous entries (e.g. pending_partition_count: int | None). Declare them as dict[str, Any], which is what model_validate accepts, annotating the first occurrence per function scope to avoid no-redef. * Add route test for legacy asset_expression served as null Per review: a pre-3.0 dataset-format asset_expression (string leaves) is served as null on /dags/{id}/details instead of 500ing the endpoint, exercising MaybeAssetExpression end-to-end. Report URL: https://github.com/apache/airflow/actions/runs/28245758792 With regards, GitHub Actions via GitBox --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
