Skip to content

Commit b521f6b

Browse files
authored
prepare v1.2 (pydantic#1042)
* making field-reuse idempotent (pydantic#1016) * making field-reuse idempotent * fix for 3.6 * correct change details * uprev * generate HISTORY.md
1 parent d9bbb05 commit b521f6b

21 files changed

+57
-20
lines changed

HISTORY.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,26 @@
1+
## v1.2 (2019-11-28)
2+
3+
* Add benchmarks for `cattrs`, #513 by @sebastianmika
4+
* Add `exclude_none` option to `dict()` and friends, #587 by @niknetniko
5+
* Add benchmarks for `valideer`, #670 by @gsakkis
6+
* Add `parse_obj_as` and `parse_file_as` functions for ad-hoc parsing of data into arbitrary pydantic-compatible types, #934 by @dmontagu
7+
* Add `allow_reuse` argument to validators, thus allowing validator reuse, #940 by @dmontagu
8+
* Add support for mapping types for custom root models, #958 by @dmontagu
9+
* Mypy plugin support for dataclasses, #966 by @koxudaxi
10+
* Add support for dataclasses default factory, #968 by @ahirner
11+
* Add a `ByteSize` type for converting byte string (`1GB`) to plain bytes, #977 by @dgasmith
12+
* Fix mypy complaint about `@root_validator(pre=True)`, #984 by @samuelcolvin
13+
* Add manylinux binaries for python 3.8 to pypi, also support manylinux2010, #994 by @samuelcolvin
14+
* Adds ByteSize conversion to another unit, #995 by @dgasmith
15+
* Fix `__str__` and `__repr__` inheritance for models, #1022 by @samuelcolvin
16+
* add testimonials section to docs, #1025 by @sullivancolin
17+
* Add support for `typing.Literal` for Python 3.8, #1026 by @dmontagu
18+
* Add support for required `Optional` with `name: Optional[AnyType] = Field(...)` and refactor `ModelField` creation to preserve `required` parameter value, #1031 by @tiangolo
19+
20+
## v1.1.1 (2019-11-20)
21+
22+
* Fix bug where use of complex fields on sub-models could cause fields to be incorrectly configured, #1015 by @samuelcolvin
23+
124
## v1.1 (2019-11-07)
225

326
* Add a mypy plugin for type checking `BaseModel.__init__` and more, #722 by @dmontagu

changes/1022-samuelcolvin.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changes/1025-sullivancolin.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changes/1026-dmontagu.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changes/1031-tiangolo.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changes/513-sebastianmika.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changes/587-niknetniko.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changes/670-gsakkis.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changes/934-dmontagu.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changes/940-dmontagu.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changes/958-dmontagu.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changes/966-koxudaxi.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changes/968-ahirner.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changes/977-dgasmith.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changes/984-samuelcolvin.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changes/994-samuelcolvin.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changes/995-dgasmith.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

pydantic/fields.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,12 @@ def alt_alias(self) -> bool:
289289
return self.name != self.alias
290290

291291
def prepare(self) -> None:
292+
"""
293+
Prepare the field but inspecting self.default, self.type_ etc.
294+
295+
Note: this method is **not** idempotent (because _type_analysis is not idempotent),
296+
e.g. calling it it multiple times may modify the field and configure it incorrectly.
297+
"""
292298
if self.default is not None and self.type_ is None:
293299
self.type_ = type(self.default)
294300

@@ -313,7 +319,7 @@ def prepare(self) -> None:
313319
self.field_info.default = Required
314320
if self.default is Undefined:
315321
self.default = None
316-
self._populate_validators()
322+
self.populate_validators()
317323

318324
def _type_analysis(self) -> None: # noqa: C901 (ignore complexity)
319325
# typing interface is horrible, we have to do some ugly checks
@@ -419,7 +425,12 @@ def _create_sub_type(self, type_: AnyType, name: str, *, for_keys: bool = False)
419425
model_config=self.model_config,
420426
)
421427

422-
def _populate_validators(self) -> None:
428+
def populate_validators(self) -> None:
429+
"""
430+
Prepare self.pre_validators, self.validators, and self.post_validators based on self.type_'s __get_validators__
431+
and class validators. This method should be idempotent, e.g. it should be safe to call multiple times
432+
without mis-configuring the field.
433+
"""
423434
class_validators_ = self.class_validators.values()
424435
if not self.sub_fields:
425436
get_validators = getattr(self.type_, '__get_validators__', None)

pydantic/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ def __new__(mcs, name, bases, namespace, **kwargs): # noqa C901
166166
if extra_validators:
167167
f.class_validators.update(extra_validators)
168168
# re-run prepare to add extra validators
169-
f.prepare()
169+
f.populate_validators()
170170

171171
prepare_config(config, name)
172172

pydantic/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
__all__ = ['VERSION']
44

5-
VERSION = StrictVersion('1.2a1')
5+
VERSION = StrictVersion('1.2')

tests/test_edge_cases.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,25 @@ class MyModel(BaseModel):
13051305
assert m.foo == {'x': 'a', 'y': None}
13061306

13071307

1308+
def test_modify_fields():
1309+
class Foo(BaseModel):
1310+
foo: List[List[int]]
1311+
1312+
@validator('foo')
1313+
def check_something(cls, value):
1314+
return value
1315+
1316+
class Bar(Foo):
1317+
pass
1318+
1319+
# output is slightly different for 3.6
1320+
if sys.version_info >= (3, 7):
1321+
assert repr(Foo.__fields__['foo']) == "ModelField(name='foo', type=List[List[int]], required=True)"
1322+
assert repr(Bar.__fields__['foo']) == "ModelField(name='foo', type=List[List[int]], required=True)"
1323+
assert Foo(foo=[[0, 1]]).foo == [[0, 1]]
1324+
assert Bar(foo=[[0, 1]]).foo == [[0, 1]]
1325+
1326+
13081327
def test_exclude_none():
13091328
class MyModel(BaseModel):
13101329
a: Optional[int] = None

0 commit comments

Comments
 (0)