Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0e1832c

Browse files
Fix make_partial_model (apache#63716)
* Fix make_partial_model * Revert "Bump pydantic min version to 2.12.3 (apache#63570)" This reverts commit 9516a77. * Fix CI
1 parent 7c77a6d commit 0e1832c

9 files changed

Lines changed: 43 additions & 13 deletions

File tree

airflow-core/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ dependencies = [
125125
'pendulum>=3.1.0',
126126
"pluggy>=1.5.0",
127127
"psutil>=5.8.0",
128-
"pydantic>=2.12.3",
128+
"pydantic>=2.11.0",
129129
# Pygments 2.19.0 improperly renders .ini files with dictionaries as values
130130
# See https://github.com/pygments/pygments/issues/2834
131131
"pygments>=2.0.1,!=2.19.0",

airflow-core/src/airflow/api_fastapi/core_api/base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
from __future__ import annotations
1818

1919
from abc import ABC, abstractmethod
20-
from copy import deepcopy
2120
from typing import TYPE_CHECKING, Generic, TypeVar, Union, get_args, get_origin
2221

2322
from pydantic import BaseModel as PydanticBaseModel, ConfigDict, create_model
@@ -54,12 +53,13 @@ def make_partial_model(model: type[PydanticBaseModel]) -> type[PydanticBaseModel
5453
"""Create a version of a Pydantic model where all fields are Optional with default=None."""
5554
field_overrides: dict = {}
5655
for field_name, field_info in model.model_fields.items():
57-
new_info = deepcopy(field_info)
5856
ann = field_info.annotation
5957
origin = get_origin(ann)
6058
if not (origin is Union and type(None) in get_args(ann)):
6159
ann = ann | None # type: ignore[operator, assignment]
60+
new_info = field_info._copy()
6261
new_info.default = None
62+
new_info._attributes_set["default"] = None
6363
field_overrides[field_name] = (ann, new_info)
6464

6565
return create_model(

airflow-core/tests/unit/api_fastapi/core_api/test_base.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@ def name_must_not_be_empty(cls, v: str) -> str:
4141
SampleModelPartial = make_partial_model(SampleModel)
4242

4343

44+
class ModelWithFieldAttributes(StrictBaseModel):
45+
"""Model with alias, title, and description to test full attribute preservation."""
46+
47+
name: str = Field(alias="user_name", title="User Name", description="The user's full name")
48+
age: int = Field(ge=0, le=150, title="Age", description="Age in years")
49+
50+
51+
ModelWithFieldAttributesPartial = make_partial_model(ModelWithFieldAttributes)
52+
53+
4454
class TestMakePartialModel:
4555
def test_all_fields_become_optional(self):
4656
instance = SampleModelPartial()
@@ -76,3 +86,23 @@ def test_already_optional_fields_stay_optional(self):
7686

7787
def test_partial_model_name(self):
7888
assert SampleModelPartial.__name__ == "SampleModelPartial"
89+
90+
def test_field_alias_preserved(self):
91+
instance = ModelWithFieldAttributesPartial(user_name="Alice")
92+
assert instance.name == "Alice"
93+
94+
def test_field_title_and_description_preserved(self):
95+
name_field = ModelWithFieldAttributesPartial.model_fields["name"]
96+
assert name_field.alias == "user_name"
97+
assert name_field.title == "User Name"
98+
assert name_field.description == "The user's full name"
99+
100+
age_field = ModelWithFieldAttributesPartial.model_fields["age"]
101+
assert age_field.title == "Age"
102+
assert age_field.description == "Age in years"
103+
104+
def test_field_ge_le_constraints_preserved(self):
105+
with pytest.raises(ValidationError):
106+
ModelWithFieldAttributesPartial(age=-1)
107+
with pytest.raises(ValidationError):
108+
ModelWithFieldAttributesPartial(age=200)

dev/registry/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ version = "0.0.1"
3333
requires-python = ">=3.10"
3434
classifiers = ["Private :: Do Not Upload"]
3535
dependencies = [
36-
"pydantic>=2.12.3",
36+
"pydantic>=2.12.0",
3737
"pyyaml>=6.0.3",
3838
]
3939

providers/edge3/docs/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ PIP package Version required
122122
========================================== ===================
123123
``apache-airflow`` ``>=3.0.0,!=3.1.0``
124124
``apache-airflow-providers-common-compat`` ``>=1.14.0``
125-
``pydantic`` ``>=2.12.3``
125+
``pydantic`` ``>=2.11.0``
126126
``retryhttp`` ``>=1.4.0``
127127
``aiofiles`` ``>=23.2.0``
128128
``aiohttp`` ``>=3.9.2``

providers/edge3/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ requires-python = ">=3.10"
6767
dependencies = [
6868
"apache-airflow>=3.0.0,!=3.1.0",
6969
"apache-airflow-providers-common-compat>=1.14.0",
70-
"pydantic>=2.12.3",
70+
"pydantic>=2.11.0",
7171
"retryhttp>=1.4.0",
7272
"aiofiles>=23.2.0",
7373
"aiohttp>=3.9.2",

shared/secrets_masker/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ dependencies = [
2727
'pendulum>=3.1.0',
2828
"methodtools>=0.4.7",
2929
"colorlog>=6.8.2",
30-
"pydantic>2.12.3",
30+
"pydantic>2.11.0",
3131
]
3232

3333
[dependency-groups]

task-sdk/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ dependencies = [
6868
# End of shared timezones dependencies
6969
# Start of shared secrets_masker dependencies
7070
"colorlog>=6.8.2",
71-
"pydantic>2.12.3",
71+
"pydantic>2.11.0",
7272
# End of shared secrets_masker dependencies
7373
# Start of shared logging dependencies
7474
"pygtrie>=2.5.0",

uv.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)