@@ -21,6 +21,15 @@ An easy way to add or create partials for Pydantic models.
21
21
22
22
[ // ] : # ( --8<-- [start:readme] )
23
23
24
+ ## Important Upgrade from v1.x Notes
25
+
26
+ I decided to make the default behavior of ` PartialModel ` not be automatic anymore.
27
+
28
+ I made a new class named ` AutoPartialModel ` that works exactly the same as the old v1.x ` PartialModel ` previously did.
29
+
30
+ To upgrade, simply replace ` PartialModel ` with ` AutoPartialModel ` , and things will work exactly as they did before.
31
+ The ` auto_partials ` configuration option is still present and if present will still override the base-class setting.
32
+
24
33
## Quick Start
25
34
26
35
### Install
@@ -41,21 +50,78 @@ You can create from scratch, or convert existing models to be Partials.
41
50
The main purpose will be to add to exiting models, and hence the default
42
51
behavior of making all non-default fields partials (configurable).
43
52
53
+ ### Two Partial Base Class Options
54
+
55
+ There are two options to inherit from:
56
+
57
+ - ` PartialModel `
58
+ - With this one, you must explicitly set which fields are partial
59
+ - To get correct static type checking, you also can also set a partial field's default value to ` Missing ` .
60
+ - ` AutoPartialModel `
61
+ - This automatically applies partial behavior to every attribute that does not already have a default value.
62
+
63
+
44
64
Let's first look at a basic example.
45
65
46
- ### Basic Example
66
+ ### Explicitly Defined Partials - Basic Example
47
67
48
- Very basic example of a simple model follows:
68
+ Very basic example of a simple model with explicitly defined partial fields, follows:
49
69
50
70
``` python
51
- from pydantic_partials import PartialModel, Missing
52
-
71
+ from pydantic_partials import PartialModel, Missing, Partial, MissingType
72
+ from pydantic import ValidationError
53
73
54
74
class MyModel (PartialModel ):
75
+ some_field: str
76
+ partial_field: Partial[str ] = Missing
77
+
78
+ # Alternate Syntax:
79
+ alternate_syntax_partial_field: str | MissingType = Missing
80
+
81
+
82
+ # By default, `Partial` fields without any value will get set to a
83
+ # special `Missing` type. Any field that is set to Missing is
84
+ # excluded from the model_dump/model_dump_json.
85
+ obj = MyModel(some_field = ' a-value' )
86
+ assert obj.partial_field is Missing
87
+ assert obj.model_dump() == {' some_field' : ' a-value' }
88
+
89
+ # You can set the real value at any time, and it will behave like expected.
90
+ obj.partial_field = ' hello'
91
+ assert obj.partial_field == ' hello'
92
+ assert obj.model_dump() == {' some_field' : ' a-value' , ' partial_field' : ' hello' }
93
+
94
+ # You can always manually set a field to `Missing` directly.
95
+ obj.partial_field = Missing
96
+
97
+ # And now it's removed from the model-dump.
98
+ assert obj.model_dump() == {' some_field' : ' a-value' }
99
+
100
+ # The json dump is also affected in the same way.
101
+ assert obj.model_dump_json() == ' {"some_field":"a-value"}'
102
+
103
+ try :
104
+ # This should produce an error because
105
+ # `some_field` is a required field.
106
+ MyModel()
107
+ except ValidationError as e:
108
+ print (f ' Pydantic will state `some_field` + `value` are required: { e} ' )
109
+ else :
110
+ raise Exception (' Pydantic should have required `some_field`.' )
111
+ ```
112
+
113
+ ### Automatically Defined Partials - Basic Example
114
+
115
+ Very basic example of a simple model with automatically defined partial fields, follows:
116
+
117
+ ``` python
118
+ from pydantic_partials import AutoPartialModel, Missing
119
+
120
+ class MyModel (AutoPartialModel ):
55
121
some_attr: str
56
122
another_field: str
57
123
58
- # By default, Partial fields without any value will get set to a
124
+ # By default, automatic defined partial fields without any value will get set to a
59
125
# special `Missing` type. Any field that is set to Missing is
60
126
# excluded from the model_dump/model_dump_json.
61
127
obj = MyModel()
@@ -91,10 +157,10 @@ This includes any inherited Pydantic fields (from a superclass).
91
157
92
158
### Inheritable
93
159
94
- You can inherit from a model to make a partial-version of the inherited fields:
160
+ With ` AutoPartialModel ` , you can inherit from a model to make an automatic partial-version of the inherited fields:
95
161
96
162
``` python
97
- from pydantic_partials import PartialModel , Missing
163
+ from pydantic_partials import AutoPartialModel , Missing
98
164
from pydantic import ValidationError, BaseModel
99
165
100
166
class TestModel (BaseModel ):
@@ -109,11 +175,11 @@ try:
109
175
except ValidationError as e:
110
176
print (f ' Pydantic will state `name` + `value` are required: { e} ' )
111
177
else :
112
- raise Exception (' Field `required_decimal` should be required.' )
178
+ raise Exception (' Pydantic should have required `required_decimal` .' )
113
179
114
180
# We inherit from `TestModel` and add `PartialModel` to the mix.
115
181
116
- class PartialTestModel (PartialModel , TestModel ):
182
+ class PartialTestModel (AutoPartialModel , TestModel ):
117
183
pass
118
184
119
185
# `PartialTestModel` can now be allocated without the required fields.
@@ -137,7 +203,7 @@ Notice that if a field has a default value, it's used instead of marking it as `
137
203
Also, the ` Missing ` sentinel value is a separate value vs ` None ` , allowing one to easily
138
204
know if a value is truly just missing or is ` None ` /` Null ` .
139
205
140
- ### Exclude Fields From Auto Partials
206
+ ### Exclude Fields from Automatic Partials (AutoPartialModel)
141
207
142
208
You can exclude specific fields from the automatic partials via these means:
143
209
@@ -155,12 +221,12 @@ You can override an excluded value by explicitly marking a field as Partial via
155
221
Here is an example using the ` AutoPartialExclude ` method, also showing how it can inherit.
156
222
157
223
``` python
158
- from pydantic_partials import PartialModel , AutoPartialExclude, Missing
224
+ from pydantic_partials import AutoPartialModel , AutoPartialExclude, Missing
159
225
from pydantic import BaseModel, ValidationError
160
226
from datetime import datetime
161
227
import pytest
162
228
163
- class PartialRequired (PartialModel ):
229
+ class PartialRequired (AutoPartialModel ):
164
230
id : AutoPartialExclude[str ]
165
231
created_at: AutoPartialExclude[datetime]
166
232
@@ -181,10 +247,11 @@ with pytest.raises(
181
247
r ' id[\w\W ]* Field required[\w\W ]* '
182
248
r ' created_at[\w\W ]* Field required'
183
249
):
184
- PartialTestModel()
250
+ # This should raise a 'ValidationError'
251
+ PartialTestModel() # type: ignore
185
252
186
253
# If we give them values, we get no ValidationError
187
- obj = PartialTestModel(id = ' some-value' , created_at = datetime.now())
254
+ obj = PartialTestModel(id = ' some-value' , created_at = datetime.now()) # type: ignore
188
255
189
256
# And fields have the expected values.
190
257
assert obj.id == ' some-value'
@@ -193,16 +260,21 @@ assert obj.name is Missing
193
260
194
261
### Auto Partials Configuration
195
262
196
- You can turn off automatically applying partials to all non-defaulted fields
197
- via ` auto_partials ` class argument or modeL_config option:
263
+ Normally you would simply inherit from either ` PartialModel ` or ` AutoPartialModel ` , depending on the desired behavior you want.
264
+
265
+ But you can also configure the auto-partials aspect via class paramters or the ` model_config ` attribute:
198
266
199
267
``` python
200
- from pydantic_partials import PartialModel, PartialConfigDict
268
+ from pydantic_partials import PartialModel, PartialConfigDict, AutoPartialModel
201
269
202
- class TestModel1 (PartialModel , auto_partials = False ):
270
+ # `PartialModel` uses `auto_partials` as `False` by default, but we can override that if you want via class argument:
271
+ class TestModel1 (PartialModel , auto_partials = True ):
203
272
...
204
273
205
- class TestModel2 (PartialModel ):
274
+ # Or via `model_config`
275
+ # (PartialConfigDict inherits from Pydantic's `ConfigDict`,
276
+ # so you have all of Pydantic's options still available).
277
+ class TestModel2 (AutoPartialModel ):
206
278
model_config = PartialConfigDict(auto_partials = False )
207
279
...
208
280
```
@@ -211,29 +283,27 @@ You can disable this automatic function. This means you have complete control of
211
283
can be partial or not. You can use either the generic ` Partial[...] ` generic or a union with ` MissingType `
212
284
to mark a field as a partial field. The generic simple makes the union to MissingType for you.
213
285
214
- Example of disabling auto_partials:
215
-
216
286
``` python
217
287
from pydantic_partials import PartialModel, Missing, MissingType, Partial
218
288
from decimal import Decimal
219
289
from pydantic import ValidationError
220
290
221
- class TestModel (PartialModel , auto_partials = False ):
291
+ class TestModel (PartialModel ):
222
292
# Can use `Partial` generic type
223
293
partial_int: Partial[int ] = Missing
224
-
294
+
225
295
# Or union with `MissingType`
226
296
partial_str: str | MissingType
227
-
297
+
228
298
required_decimal: Decimal
229
-
299
+
230
300
try :
231
301
TestModel()
232
302
except ValidationError as e:
233
303
print (f ' Pydantic will state `required_decimal` is required: { e} ' )
234
304
else :
235
305
raise Exception (' Pydantic should have required `required_decimal`.' )
236
-
306
+
237
307
obj = TestModel(required_decimal = ' 1.34' )
238
308
239
309
# You can find out at any time if a field is missing or not:
0 commit comments