Skip to content

Commit

Permalink
Add base model for rest api; set from_attributes=True (apache#44267)
Browse files Browse the repository at this point in the history
This enables us to have simpler API code, since we don't need to call `model_validate` as much.
  • Loading branch information
dstandish authored Nov 22, 2024
1 parent 4f8cb6e commit 208f07b
Show file tree
Hide file tree
Showing 48 changed files with 166 additions and 146 deletions.
29 changes: 29 additions & 0 deletions airflow/api_fastapi/core_api/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# 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.
from __future__ import annotations

from pydantic import BaseModel as PydanticBaseModel, ConfigDict


class BaseModel(PydanticBaseModel):
"""
Base pydantic model for REST API.
:meta private:
"""

model_config = ConfigDict(from_attributes=True)
3 changes: 2 additions & 1 deletion airflow/api_fastapi/core_api/datamodels/assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@

from datetime import datetime

from pydantic import BaseModel, Field, field_validator
from pydantic import Field, field_validator

from airflow.api_fastapi.core_api.base import BaseModel
from airflow.utils.log.secrets_masker import redact


Expand Down
3 changes: 1 addition & 2 deletions airflow/api_fastapi/core_api/datamodels/backfills.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@

from datetime import datetime

from pydantic import BaseModel

from airflow.api_fastapi.core_api.base import BaseModel
from airflow.models.backfill import ReprocessBehavior


Expand Down
2 changes: 1 addition & 1 deletion airflow/api_fastapi/core_api/datamodels/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# under the License.
from __future__ import annotations

from pydantic import BaseModel
from airflow.api_fastapi.core_api.base import BaseModel


class ConfigOption(BaseModel):
Expand Down
3 changes: 2 additions & 1 deletion airflow/api_fastapi/core_api/datamodels/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@

import json

from pydantic import BaseModel, Field, field_validator
from pydantic import Field, field_validator
from pydantic_core.core_schema import ValidationInfo

from airflow.api_fastapi.core_api.base import BaseModel
from airflow.utils.log.secrets_masker import redact


Expand Down
3 changes: 2 additions & 1 deletion airflow/api_fastapi/core_api/datamodels/dag_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@
from datetime import datetime
from enum import Enum

from pydantic import BaseModel, Field
from pydantic import Field

from airflow.api_fastapi.core_api.base import BaseModel
from airflow.utils.state import DagRunState
from airflow.utils.types import DagRunTriggeredByType, DagRunType

Expand Down
2 changes: 1 addition & 1 deletion airflow/api_fastapi/core_api/datamodels/dag_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# under the License.
from __future__ import annotations

from pydantic import BaseModel
from airflow.api_fastapi.core_api.base import BaseModel


class DAGSourceResponse(BaseModel):
Expand Down
3 changes: 1 addition & 2 deletions airflow/api_fastapi/core_api/datamodels/dag_stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@

from __future__ import annotations

from pydantic import BaseModel

from airflow.api_fastapi.core_api.base import BaseModel
from airflow.utils.state import DagRunState


Expand Down
3 changes: 1 addition & 2 deletions airflow/api_fastapi/core_api/datamodels/dag_warning.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@

from datetime import datetime

from pydantic import BaseModel

from airflow.api_fastapi.core_api.base import BaseModel
from airflow.models.dagwarning import DagWarningType


Expand Down
25 changes: 13 additions & 12 deletions airflow/api_fastapi/core_api/datamodels/dags.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@
from pendulum.tz.timezone import FixedTimezone, Timezone
from pydantic import (
AliasGenerator,
BaseModel,
ConfigDict,
computed_field,
field_validator,
)

from airflow.api_fastapi.core_api.base import BaseModel
from airflow.configuration import conf
from airflow.serialization.pydantic.dag import DagTagPydantic

Expand Down Expand Up @@ -107,6 +107,17 @@ class DAGCollectionResponse(BaseModel):
class DAGDetailsResponse(DAGResponse):
"""Specific serializer for DAG Details responses."""

model_config = ConfigDict(
from_attributes=True,
alias_generator=AliasGenerator(
validation_alias=lambda field_name: {
"dag_run_timeout": "dagrun_timeout",
"last_parsed": "last_loaded",
"template_search_path": "template_searchpath",
}.get(field_name, field_name),
),
)

catchup: bool
dag_run_timeout: timedelta | None
asset_expression: dict | None
Expand All @@ -120,16 +131,6 @@ class DAGDetailsResponse(DAGResponse):
timezone: str | None
last_parsed: datetime | None

model_config = ConfigDict(
alias_generator=AliasGenerator(
validation_alias=lambda field_name: {
"dag_run_timeout": "dagrun_timeout",
"last_parsed": "last_loaded",
"template_search_path": "template_searchpath",
}.get(field_name, field_name),
)
)

@field_validator("timezone", mode="before")
@classmethod
def get_timezone(cls, tz: Timezone | FixedTimezone) -> str | None:
Expand All @@ -144,7 +145,7 @@ def get_params(cls, params: abc.MutableMapping | None) -> dict | None:
"""Convert params attribute to dict representation."""
if params is None:
return None
return {param_name: param_val.dump() for param_name, param_val in params.items()}
return {k: v.dump() for k, v in params.items()}

# Mypy issue https://github.com/python/mypy/issues/1362
@computed_field # type: ignore[misc]
Expand Down
8 changes: 5 additions & 3 deletions airflow/api_fastapi/core_api/datamodels/event_logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,16 @@

from datetime import datetime

from pydantic import BaseModel, ConfigDict, Field
from pydantic import ConfigDict, Field

from airflow.api_fastapi.core_api.base import BaseModel


class EventLogResponse(BaseModel):
"""Event Log Response."""

model_config = ConfigDict(populate_by_name=True, from_attributes=True)

id: int = Field(alias="event_log_id")
dttm: datetime = Field(alias="when")
dag_id: str | None
Expand All @@ -37,8 +41,6 @@ class EventLogResponse(BaseModel):
owner: str | None
extra: str | None

model_config = ConfigDict(populate_by_name=True)


class EventLogCollectionResponse(BaseModel):
"""Event Log Collection Response."""
Expand Down
8 changes: 5 additions & 3 deletions airflow/api_fastapi/core_api/datamodels/import_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,21 @@

from datetime import datetime

from pydantic import BaseModel, ConfigDict, Field
from pydantic import ConfigDict, Field

from airflow.api_fastapi.core_api.base import BaseModel


class ImportErrorResponse(BaseModel):
"""Import Error Response."""

model_config = ConfigDict(populate_by_name=True, from_attributes=True)

id: int = Field(alias="import_error_id")
timestamp: datetime
filename: str
stacktrace: str = Field(alias="stack_trace")

model_config = ConfigDict(populate_by_name=True)


class ImportErrorCollectionResponse(BaseModel):
"""Import Error Collection Response."""
Expand Down
4 changes: 1 addition & 3 deletions airflow/api_fastapi/core_api/datamodels/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,12 @@

from datetime import datetime

from pydantic import BaseModel, ConfigDict
from airflow.api_fastapi.core_api.base import BaseModel


class JobResponse(BaseModel):
"""Job serializer for responses."""

model_config = ConfigDict(populate_by_name=True)

id: int
dag_id: str | None
state: str | None
Expand Down
2 changes: 1 addition & 1 deletion airflow/api_fastapi/core_api/datamodels/monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# under the License.
from __future__ import annotations

from pydantic import BaseModel
from airflow.api_fastapi.core_api.base import BaseModel


class BaseInfoSchema(BaseModel):
Expand Down
3 changes: 2 additions & 1 deletion airflow/api_fastapi/core_api/datamodels/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@

from typing import Annotated, Any

from pydantic import BaseModel, BeforeValidator, ConfigDict, field_validator
from pydantic import BeforeValidator, ConfigDict, field_validator

from airflow.api_fastapi.core_api.base import BaseModel
from airflow.plugins_manager import AirflowPluginSource


Expand Down
6 changes: 4 additions & 2 deletions airflow/api_fastapi/core_api/datamodels/pools.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@

from typing import Annotated, Callable

from pydantic import BaseModel, BeforeValidator, ConfigDict, Field
from pydantic import BeforeValidator, ConfigDict, Field

from airflow.api_fastapi.core_api.base import BaseModel


def _call_function(function: Callable[[], int]) -> int:
Expand Down Expand Up @@ -61,7 +63,7 @@ class PoolCollectionResponse(BaseModel):
class PoolPatchBody(BaseModel):
"""Pool serializer for patch bodies."""

model_config = ConfigDict(populate_by_name=True)
model_config = ConfigDict(populate_by_name=True, from_attributes=True)

name: str | None = Field(default=None, alias="pool")
slots: int | None = None
Expand Down
2 changes: 1 addition & 1 deletion airflow/api_fastapi/core_api/datamodels/providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

from __future__ import annotations

from pydantic import BaseModel
from airflow.api_fastapi.core_api.base import BaseModel


class ProviderResponse(BaseModel):
Expand Down
9 changes: 6 additions & 3 deletions airflow/api_fastapi/core_api/datamodels/task_instances.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
from pydantic import (
AliasPath,
AwareDatetime,
BaseModel,
BeforeValidator,
ConfigDict,
Field,
Expand All @@ -31,6 +30,7 @@
model_validator,
)

from airflow.api_fastapi.core_api.base import BaseModel
from airflow.api_fastapi.core_api.datamodels.job import JobResponse
from airflow.api_fastapi.core_api.datamodels.trigger import TriggerResponse
from airflow.utils.state import TaskInstanceState
Expand All @@ -39,7 +39,7 @@
class TaskInstanceResponse(BaseModel):
"""TaskInstance serializer for responses."""

model_config = ConfigDict(populate_by_name=True)
model_config = ConfigDict(populate_by_name=True, from_attributes=True)

id: str
task_id: str
Expand Down Expand Up @@ -121,11 +121,14 @@ class TaskInstancesBatchBody(BaseModel):
class TaskInstanceHistoryResponse(BaseModel):
"""TaskInstanceHistory serializer for responses."""

model_config = ConfigDict(populate_by_name=True)
model_config = ConfigDict(populate_by_name=True, from_attributes=True)

task_id: str
dag_id: str

# todo: this should not be aliased; it's ambiguous with dag run's "id" - airflow 3.0
run_id: str = Field(alias="dag_run_id")

map_index: int
start_date: datetime | None
end_date: datetime | None
Expand Down
3 changes: 2 additions & 1 deletion airflow/api_fastapi/core_api/datamodels/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@
from datetime import datetime
from typing import Any

from pydantic import BaseModel, computed_field, field_validator, model_validator
from pydantic import computed_field, field_validator, model_validator

from airflow.api_fastapi.common.types import TimeDeltaWithValidation
from airflow.api_fastapi.core_api.base import BaseModel
from airflow.models.mappedoperator import MappedOperator
from airflow.serialization.serialized_objects import SerializedBaseOperator, encode_priority_weight_strategy
from airflow.task.priority_strategy import PriorityWeightStrategy
Expand Down
4 changes: 3 additions & 1 deletion airflow/api_fastapi/core_api/datamodels/trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
from datetime import datetime
from typing import Annotated

from pydantic import BaseModel, BeforeValidator, ConfigDict
from pydantic import BeforeValidator, ConfigDict

from airflow.api_fastapi.core_api.base import BaseModel


class TriggerResponse(BaseModel):
Expand Down
3 changes: 1 addition & 2 deletions airflow/api_fastapi/core_api/datamodels/ui/dags.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@

from __future__ import annotations

from pydantic import BaseModel

from airflow.api_fastapi.core_api.base import BaseModel
from airflow.api_fastapi.core_api.datamodels.dag_run import DAGRunResponse
from airflow.api_fastapi.core_api.datamodels.dags import DAGResponse

Expand Down
2 changes: 1 addition & 1 deletion airflow/api_fastapi/core_api/datamodels/ui/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# under the License.
from __future__ import annotations

from pydantic import BaseModel
from airflow.api_fastapi.core_api.base import BaseModel


class DAGRunTypes(BaseModel):
Expand Down
5 changes: 3 additions & 2 deletions airflow/api_fastapi/core_api/datamodels/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,17 @@

import json

from pydantic import BaseModel, ConfigDict, Field, model_validator
from pydantic import ConfigDict, Field, model_validator

from airflow.api_fastapi.core_api.base import BaseModel
from airflow.typing_compat import Self
from airflow.utils.log.secrets_masker import redact


class VariableResponse(BaseModel):
"""Variable serializer for responses."""

model_config = ConfigDict(populate_by_name=True)
model_config = ConfigDict(populate_by_name=True, from_attributes=True)

key: str
val: str | None = Field(alias="value")
Expand Down
2 changes: 1 addition & 1 deletion airflow/api_fastapi/core_api/datamodels/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# under the License.
from __future__ import annotations

from pydantic import BaseModel
from airflow.api_fastapi.core_api.base import BaseModel


class VersionInfo(BaseModel):
Expand Down
Loading

0 comments on commit 208f07b

Please sign in to comment.