Skip to content

Commit 5077533

Browse files
committed
Move all_fields_optional_model decorator to view models utils module for reusability
1 parent 8391f67 commit 5077533

File tree

2 files changed

+39
-33
lines changed

2 files changed

+39
-33
lines changed

src/mavedb/view_models/score_set.py

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@
22
from __future__ import annotations
33

44
import json
5-
from copy import deepcopy
65
from datetime import date
7-
from typing import Any, Callable, Collection, Optional, Sequence, Type, TypeVar, Union
6+
from typing import Any, Collection, Optional, Sequence, Union
87

9-
from pydantic import create_model, field_validator, model_validator
10-
from pydantic.fields import FieldInfo
8+
from pydantic import field_validator, model_validator
119
from typing_extensions import Self
1210

1311
from mavedb.lib.validation import urn_re
@@ -42,38 +40,10 @@
4240
TargetGeneCreate,
4341
)
4442
from mavedb.view_models.user import SavedUser, User
43+
from mavedb.view_models.utils import all_fields_optional_model
4544

4645
UnboundedRange = tuple[Union[float, None], Union[float, None]]
4746

48-
Model = TypeVar("Model", bound=BaseModel)
49-
50-
51-
def all_fields_optional_model() -> Callable[[Type[Model]], Type[Model]]:
52-
"""A decorator that create a partial model.
53-
54-
Args:
55-
model (Type[BaseModel]): BaseModel model.
56-
57-
Returns:
58-
Type[BaseModel]: ModelBase partial model.
59-
"""
60-
61-
def wrapper(model: Type[Model]) -> Type[Model]:
62-
def make_field_optional(field: FieldInfo, default: Any = None) -> tuple[Any, FieldInfo]:
63-
new = deepcopy(field)
64-
new.default = default
65-
new.annotation = Optional[field.annotation] # type: ignore[assignment]
66-
return new.annotation, new
67-
68-
return create_model(
69-
model.__name__,
70-
__base__=model,
71-
__module__=model.__module__,
72-
**{field_name: make_field_optional(field_info) for field_name, field_info in model.model_fields.items()},
73-
) # type: ignore[call-overload]
74-
75-
return wrapper
76-
7747

7848
class ExternalLink(BaseModel):
7949
url: Optional[str] = None

src/mavedb/view_models/utils.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from copy import deepcopy
2+
from typing import Any, Callable, Optional, Type, TypeVar
3+
4+
from pydantic import create_model
5+
from pydantic.fields import FieldInfo
6+
7+
from mavedb.view_models.base.base import BaseModel
8+
9+
Model = TypeVar("Model", bound=BaseModel)
10+
11+
12+
def all_fields_optional_model() -> Callable[[Type[Model]], Type[Model]]:
13+
"""A decorator that create a partial model.
14+
15+
Args:
16+
model (Type[BaseModel]): BaseModel model.
17+
18+
Returns:
19+
Type[BaseModel]: ModelBase partial model.
20+
"""
21+
22+
def wrapper(model: Type[Model]) -> Type[Model]:
23+
def make_field_optional(field: FieldInfo, default: Any = None) -> tuple[Any, FieldInfo]:
24+
new = deepcopy(field)
25+
new.default = default
26+
new.annotation = Optional[field.annotation] # type: ignore[assignment]
27+
return new.annotation, new
28+
29+
return create_model(
30+
model.__name__,
31+
__base__=model,
32+
__module__=model.__module__,
33+
**{field_name: make_field_optional(field_info) for field_name, field_info in model.model_fields.items()},
34+
) # type: ignore[call-overload]
35+
36+
return wrapper

0 commit comments

Comments
 (0)