55"""
66
77import dataclasses
8+ import warnings
89from typing import Any
910
11+ from typing_extensions import TypeVar , deprecated , overload
12+
1013from validataclass .validators import Validator
11- from .defaults import BaseDefault , Default , NoDefault
14+ from .defaults import BaseDefault , Default , NoDefault , _NoDefaultType
1215
1316__all__ = [
1417 'validataclass_field' ,
1518]
1619
20+ T_Validated = TypeVar ('T_Validated' )
21+ T_Default = TypeVar ('T_Default' )
22+
23+
24+ # NOTE: Actual return type of this function is `Field[T_Validated | T_Default]`. However, we will pretend here that it
25+ # returns `T_Validated | T_Default` instead, to help type checkers understand what happens within the context of a
26+ # dataclass. This is the same thing that typeshed does.
27+ # (Using this function outside the context of a dataclass usually doesn't make a lot of sense.)
28+
29+ @overload
30+ def validataclass_field (
31+ validator : Validator [T_Validated ],
32+ * ,
33+ default : _NoDefaultType = NoDefault ,
34+ metadata : dict [str , Any ] | None = None ,
35+ ** kwargs : Any ,
36+ ) -> T_Validated :
37+ ...
38+
39+
40+ @overload
41+ def validataclass_field (
42+ validator : Validator [T_Validated ],
43+ * ,
44+ default : BaseDefault [T_Default ],
45+ metadata : dict [str , Any ] | None = None ,
46+ ** kwargs : Any ,
47+ ) -> T_Validated | T_Default :
48+ ...
49+
50+
51+ @overload
52+ @deprecated ('Use default objects instead of raw defaults or dataclasses.MISSING' )
53+ def validataclass_field (
54+ validator : Validator [T_Validated ],
55+ * ,
56+ default : Any ,
57+ metadata : dict [str , Any ] | None = None ,
58+ ** kwargs : Any ,
59+ ) -> Any :
60+ ...
61+
1762
1863def validataclass_field (
19- validator : Validator [Any ],
20- default : Any = NoDefault ,
64+ validator : Validator [T_Validated ],
2165 * ,
66+ default : BaseDefault [T_Default ] | Any = NoDefault ,
2267 metadata : dict [str , Any ] | None = None ,
2368 ** kwargs : Any ,
2469) -> Any :
@@ -29,15 +74,15 @@ def validataclass_field(
2974
3075 Additional keyword arguments will be passed to `dataclasses.field()`, with some exceptions:
3176
32- - `default` is handled by this function to set metadata. It can be either a direct value or a validataclass default
33- object, i.e. an object of a subclass of `BaseDefault` (e.g. `Default`, ` DefaultFactory`, `NoDefault`).
34- It is then converted to a direct value (or factory) if necessary and passed to `dataclasses.field()` .
77+ - `default` is handled by this function to set metadata. It must be a validataclass default object (e.g. an instance
78+ of `Default` or ` DefaultFactory`, or the special value `NoDefault`). Using raw default values is **deprecated**
79+ and won't be supported in the future. The same applies to the `dataclasses.MISSING` sentinel .
3580 - `default_factory` is not allowed. Use `default=DefaultFactory(...)` instead.
3681 - `init` is not allowed. To create a non-init field, use `dataclasses.field(init=False)` instead.
3782
3883 Parameters:
3984 `validator`: Validator to use for validating the field (subclass of `Validator`).
40- `default`: Default value when the field is missing in the input data (any value or subclass of `BaseDefault`).
85+ `default`: Default value when the field is missing ( subclass of `BaseDefault`, defaults to `NoDefault `).
4186 `metadata`: Base dictionary for field metadata, gets merged with the metadata generated by this function.
4287 `**kwargs`: Additional keyword arguments that are passed to `dataclasses.field()`.
4388 """
@@ -47,21 +92,32 @@ def validataclass_field(
4792
4893 # Check for incompatible keyword arguments
4994 if 'init' in kwargs :
50- raise ValueError ('Keyword argument "init" is not allowed in validator field .' )
95+ raise ValueError ('Keyword argument "init" is not allowed in validataclass_field .' )
5196 if 'default_factory' in kwargs :
5297 raise ValueError (
53- 'Keyword argument "default_factory" is not allowed in validator field (use default=DefaultFactory(...) '
98+ 'Keyword argument "default_factory" is not allowed in validataclass_field (use default=DefaultFactory(...) '
5499 'instead).'
55100 )
56101
57102 # Add validator metadata
58103 metadata ['validator' ] = validator
59104
60105 # Ensure default is a validataclass default object (any subclass of BaseDefault)
106+ # TODO: Remove deprecated behaviour for raw defaults and dataclasses.MISSING in a future version.
61107 if default is dataclasses .MISSING :
108+ warnings .warn (
109+ 'Using validataclass_field() with `default=dataclasses.MISSING` is deprecated. '
110+ 'Please use `default=NoDefault` instead.' ,
111+ DeprecationWarning
112+ )
62113 default = NoDefault
63114 elif not isinstance (default , BaseDefault ):
64115 # Wrap value in a validataclass default object
116+ warnings .warn (
117+ 'Using validataclass_field() with raw default values is deprecated. '
118+ 'Please use default objects instead (e.g. `default=Default(...)`).' ,
119+ DeprecationWarning
120+ )
65121 default = Default (default )
66122
67123 if default is not NoDefault :
0 commit comments