Skip to content

Commit

Permalink
Merge branch 'master' into pydanticGH-3444
Browse files Browse the repository at this point in the history
  • Loading branch information
PrettyWood committed Dec 8, 2021
2 parents 0297d99 + 7421579 commit a5601ad
Show file tree
Hide file tree
Showing 43 changed files with 991 additions and 129 deletions.
26 changes: 13 additions & 13 deletions HISTORY.md
Expand Up @@ -60,7 +60,7 @@ for their kind support.
* Improve field declaration for _pydantic_ `dataclass` by allowing the usage of _pydantic_ `Field` or `'metadata'` kwarg of `dataclasses.field`, #2384 by @PrettyWood
* Making `typing-extensions` a required dependency, #2368 by @samuelcolvin
* Make `resolve_annotations` more lenient, allowing for missing modules, #2363 by @samuelcolvin
* Allow configuring models through class kwargs, #2356 by @MrMrRobat
* Allow configuring models through class kwargs, #2356 by @Bobronium
* Prevent `Mapping` subclasses from always being coerced to `dict`, #2325 by @ofek
* fix: allow `None` for type `Optional[conset / conlist]`, #2320 by @PrettyWood
* Support empty tuple type, #2318 by @PrettyWood
Expand Down Expand Up @@ -142,7 +142,7 @@ Thank you to pydantic's sponsors:

## v1.7.2 (2020-11-01)

* fix slow `GenericModel` concrete model creation, allow `GenericModel` concrete name reusing in module, #2078 by @MrMrRobat
* fix slow `GenericModel` concrete model creation, allow `GenericModel` concrete name reusing in module, #2078 by @Bobronium
* keep the order of the fields when `validate_assignment` is set, #2073 by @PrettyWood
* forward all the params of the stdlib `dataclass` when converted into _pydantic_ `dataclass`, #2065 by @PrettyWood

Expand All @@ -168,7 +168,7 @@ for their kind support.
### Highlights

* python 3.9 support, thanks @PrettyWood
* [Private model attributes](https://pydantic-docs.helpmanual.io/usage/models/#private-model-attributes), thanks @MrMrRobat
* [Private model attributes](https://pydantic-docs.helpmanual.io/usage/models/#private-model-attributes), thanks @Bobronium
* ["secrets files" support in `BaseSettings`](https://pydantic-docs.helpmanual.io/usage/settings/#secret-support), thanks @mdgilene
* [convert stdlib dataclasses to pydantic dataclasses and use stdlib dataclasses in models](https://pydantic-docs.helpmanual.io/usage/dataclasses/#stdlib-dataclasses-and-pydantic-dataclasses), thanks @PrettyWood

Expand Down Expand Up @@ -205,8 +205,8 @@ for their kind support.
* add `Enum` and `IntEnum` as valid types for fields, #1735 by @PrettyWood
* Change default value of `__module__` argument of `create_model` from `None` to `'pydantic.main'`.
Set reference of created concrete model to it's module to allow pickling (not applied to models created in
functions), #1686 by @MrMrRobat
* Add private attributes support, #1679 by @MrMrRobat
functions), #1686 by @Bobronium
* Add private attributes support, #1679 by @Bobronium
* add `config` to `@validate_arguments`, #1663 by @samuelcolvin
* Allow descendant Settings models to override env variable names for the fields defined in parent Settings models with
`env` in their `Config`. Previously only `env_prefix` configuration option was applicable, #1561 by @ojomio
Expand Down Expand Up @@ -257,7 +257,7 @@ Thank you to pydantic's sponsors: @matin, @tiangolo, @chdsbd, @jorgecarleitao, a
* Avoid some side effects of `default_factory` by calling it only once
if possible and by not setting a default value in the schema, #1491 by @PrettyWood
* Added docs about dumping dataclasses to JSON, #1487 by @mikegrima
* Make `BaseModel.__signature__` class-only, so getting `__signature__` from model instance will raise `AttributeError`, #1466 by @MrMrRobat
* Make `BaseModel.__signature__` class-only, so getting `__signature__` from model instance will raise `AttributeError`, #1466 by @Bobronium
* include `'format': 'password'` in the schema for secret types, #1424 by @atheuz
* Modify schema constraints on `ConstrainedFloat` so that `exclusiveMinimum` and
minimum are not included in the schema if they are equal to `-math.inf` and
Expand Down Expand Up @@ -306,8 +306,8 @@ Thank you to pydantic's sponsors: @matin, @tiangolo, @chdsbd, @jorgecarleitao, a
* fix mypy signature for `root_validator`, #1192 by @samuelcolvin
* Fixed parsing of nested 'custom root type' models, #1190 by @Shados
* Add `validate_arguments` function decorator which checks the arguments to a function matches type annotations, #1179 by @samuelcolvin
* Add `__signature__` to models, #1034 by @MrMrRobat
* Refactor `._iter()` method, 10x speed boost for `dict(model)`, #1017 by @MrMrRobat
* Add `__signature__` to models, #1034 by @Bobronium
* Refactor `._iter()` method, 10x speed boost for `dict(model)`, #1017 by @Bobronium

## v1.4 (2020-01-24)

Expand Down Expand Up @@ -485,7 +485,7 @@ Thank you to pydantic's sponsors: @matin, @tiangolo, @chdsbd, @jorgecarleitao, a

* add model name to `ValidationError` error message, #676 by @dmontagu
* **breaking change**: remove `__getattr__` and rename `__values__` to `__dict__` on `BaseModel`,
deprecation warning on use `__values__` attr, attributes access speed increased up to 14 times, #712 by @MrMrRobat
deprecation warning on use `__values__` attr, attributes access speed increased up to 14 times, #712 by @Bobronium
* support `ForwardRef` (without self-referencing annotations) in Python 3.6, #706 by @koxudaxi
* implement `schema_extra` in `Config` sub-class, #663 by @tiangolo

Expand All @@ -498,12 +498,12 @@ Thank you to pydantic's sponsors: @matin, @tiangolo, @chdsbd, @jorgecarleitao, a

* better support for floating point `multiple_of` values, #652 by @justindujardin
* fix schema generation for `NewType` and `Literal`, #649 by @dmontagu
* fix `alias_generator` and field config conflict, #645 by @gmetzker and #658 by @MrMrRobat
* fix `alias_generator` and field config conflict, #645 by @gmetzker and #658 by @Bobronium
* more detailed message for `EnumError`, #673 by @dmontagu
* add advanced exclude support for `dict`, `json` and `copy`, #648 by @MrMrRobat
* add advanced exclude support for `dict`, `json` and `copy`, #648 by @Bobronium
* fix bug in `GenericModel` for models with concrete parameterized fields, #672 by @dmontagu
* add documentation for `Literal` type, #651 by @dmontagu
* add `Config.keep_untouched` for custom descriptors support, #679 by @MrMrRobat
* add `Config.keep_untouched` for custom descriptors support, #679 by @Bobronium
* use `inspect.cleandoc` internally to get model description, #657 by @tiangolo
* add `Color` to schema generation, by @euri10
* add documentation for Literal type, #651 by @dmontagu
Expand All @@ -520,7 +520,7 @@ Thank you to pydantic's sponsors: @matin, @tiangolo, @chdsbd, @jorgecarleitao, a
* fix default values for `GenericModel`, #610 by @dmontagu
* clarify that self-referencing models require python 3.7+, #616 by @vlcinsky
* fix truncate for types, #611 by @dmontagu
* add `alias_generator` support, #622 by @MrMrRobat
* add `alias_generator` support, #622 by @Bobronium
* fix unparameterized generic type schema generation, #625 by @dmontagu
* fix schema generation with multiple/circular references to the same model, #621 by @tiangolo and @wongpat
* support custom root types, #628 by @koxudaxi
Expand Down
1 change: 1 addition & 0 deletions changes/1897-PrettyWood.md
@@ -0,0 +1 @@
add `confrozenset()`, analogous to `conset()` and `conlist()`
1 change: 1 addition & 0 deletions changes/2007-diabolo-dan.md
@@ -0,0 +1 @@
Add parameterised subclasses to `__bases__` when constructing new parameterised classes, so that `A <: B => A[int] <: B[int]`.
1 change: 1 addition & 0 deletions changes/2092-PrettyWood.md
@@ -0,0 +1 @@
add `Config.smart_union` to prevent coercion in `Union` if possible. See [the doc](https://pydantic-docs.helpmanual.io/usage/model_config/#smart-union) for more information
1 change: 1 addition & 0 deletions changes/2497-PrettyWood.md
@@ -0,0 +1 @@
Set `minItems` and `maxItems` in generated JSON schema for fixed-length tuples
1 change: 1 addition & 0 deletions changes/2588-uriyyo.md
@@ -0,0 +1 @@
Try to evaluate forward refs automatically at model creation.
1 change: 1 addition & 0 deletions changes/2650-PrettyWood.md
@@ -0,0 +1 @@
Make serialization of referenced pydantic models possible
1 change: 1 addition & 0 deletions changes/2697-sammchardy.md
@@ -0,0 +1 @@
`Enum` fields now properly support extra kwargs in schema generation
9 changes: 8 additions & 1 deletion docs/build/schema_mapping.py
Expand Up @@ -81,10 +81,17 @@
'JSON Schema Validation',
'And equivalently for any other sub type, e.g. `List[int]`.'
],
[
'Tuple[str, ...]',
'array',
{'items': {'type': 'string'}},
'JSON Schema Validation',
'And equivalently for any other sub type, e.g. `Tuple[int, ...]`.'
],
[
'Tuple[str, int]',
'array',
{'items': [{'type': 'string'}, {'type': 'integer'}]},
{'items': [{'type': 'string'}, {'type': 'integer'}], 'minItems': 2, 'maxItems': 2},
'JSON Schema Validation',
(
'And equivalently for any other set of subtypes. Note: If using schemas for OpenAPI, '
Expand Down
34 changes: 34 additions & 0 deletions docs/examples/exporting_models_json_forward_ref.py
@@ -0,0 +1,34 @@
from typing import List, Optional

from pydantic import BaseModel


class Address(BaseModel):
city: str
country: str


class User(BaseModel):
name: str
address: Address
friends: Optional[List['User']] = None

class Config:
json_encoders = {
Address: lambda a: f'{a.city} ({a.country})',
'User': lambda u: f'{u.name} in {u.address.city} '
f'({u.address.country[:2].upper()})',
}


User.update_forward_refs()

wolfgang = User(
name='Wolfgang',
address=Address(city='Berlin', country='Deutschland'),
friends=[
User(name='Pierre', address=Address(city='Paris', country='France')),
User(name='John', address=Address(city='London', country='UK')),
],
)
print(wolfgang.json())
19 changes: 19 additions & 0 deletions docs/examples/model_config_smart_union_off.py
@@ -0,0 +1,19 @@
from typing import Union

from pydantic import BaseModel


class Foo(BaseModel):
pass


class Bar(BaseModel):
pass


class Model(BaseModel):
x: Union[str, int]
y: Union[Foo, Bar]


print(Model(x=1, y=Bar()))
22 changes: 22 additions & 0 deletions docs/examples/model_config_smart_union_on.py
@@ -0,0 +1,22 @@
from typing import Union

from pydantic import BaseModel


class Foo(BaseModel):
pass


class Bar(BaseModel):
pass


class Model(BaseModel):
x: Union[str, int]
y: Union[Foo, Bar]

class Config:
smart_union = True


print(Model(x=1, y=Bar()))
14 changes: 14 additions & 0 deletions docs/examples/model_config_smart_union_on_edge_case.py
@@ -0,0 +1,14 @@
from typing import List, Union

from pydantic import BaseModel


class Model(BaseModel, smart_union=True):
x: Union[List[str], List[int]]


# Expected coercion
print(Model(x=[1, '2']))

# Unexpected coercion
print(Model(x=[1, 2]))
4 changes: 2 additions & 2 deletions docs/examples/models_generics_naming.py
Expand Up @@ -13,5 +13,5 @@ def __concrete_name__(cls: Type[Any], params: Tuple[Type[Any], ...]) -> str:
return f'{params[0].__name__.title()}Response'


print(Response[int](data=1))
print(Response[str](data='a'))
print(repr(Response[int](data=1)))
print(repr(Response[str](data='a')))
Expand Up @@ -8,7 +8,5 @@ class Foo(BaseModel):
sibling: Foo = None


Foo.update_forward_refs()

print(Foo())
print(Foo(sibling={'a': '321'}))
Expand Up @@ -7,7 +7,5 @@ class Foo(BaseModel):
sibling: 'Foo' = None


Foo.update_forward_refs()

print(Foo())
print(Foo(sibling={'a': '321'}))
4 changes: 2 additions & 2 deletions docs/requirements.txt
@@ -1,12 +1,12 @@
ansi2html==1.6.0
flake8==4.0.1
flake8-quotes==3.3.1
hypothesis==6.24.0
hypothesis==6.30.1
markdown-include==0.6.0
mdx-truly-sane-lists==1.2
mkdocs==1.2.3
mkdocs-exclude==1.0.2
mkdocs-material==7.3.4
mkdocs-material==8.0.5
sqlalchemy
orjson
ujson
10 changes: 9 additions & 1 deletion docs/usage/exporting_models.md
Expand Up @@ -88,7 +88,7 @@ _(This script is complete, it should run "as is")_

### `json_encoders`

Serialisation can be customised on a model using the `json_encoders` config property; the keys should be types, and
Serialisation can be customised on a model using the `json_encoders` config property; the keys should be types (or names of types for forward references), and
the values should be functions which serialise that type (see the example below):

```py
Expand All @@ -107,6 +107,14 @@ encoders taking precedence over the parent one.
```
_(This script is complete, it should run "as is")_

### Serialising self-reference or other models

In case of forward references, you can use a string with the class name instead of the class itself
```py
{!.tmp_examples/exporting_models_json_forward_ref.py!}
```
_(This script is complete, it should run "as is")_

### Serialising subclasses

!!! note
Expand Down
32 changes: 31 additions & 1 deletion docs/usage/model_config.md
Expand Up @@ -113,7 +113,10 @@ not be included in the model schemas. **Note**: this means that attributes on th
: whether to treat any underscore non-class var attrs as private, or leave them as is; See [Private model attributes](models.md#private-model-attributes)

**`copy_on_model_validation`**
: whether or not inherited models used as fields should be reconstructed (copied) on validation instead of being kept untouched (default: `True`)
: whether inherited models used as fields should be reconstructed (copied) on validation instead of being kept untouched (default: `True`)

**`smart_union`**
: whether _pydantic_ should try to check all types inside `Union` to prevent undesired coercion (see [the dedicated section](#smart-union)

## Change behaviour globally

Expand Down Expand Up @@ -164,3 +167,30 @@ For example:
{!.tmp_examples/model_config_alias_precedence.py!}
```
_(This script is complete, it should run "as is")_

## Smart Union

By default, as explained [here](types.md#unions), _pydantic_ tries to validate (and coerce if it can) in the order of the `Union`.
So sometimes you may have unexpected coerced data.

```py
{!.tmp_examples/model_config_smart_union_off.py!}
```
_(This script is complete, it should run "as is")_

To prevent this, you can enable `Config.smart_union`. _Pydantic_ will then check all allowed types before even trying to coerce.
Know that this is of course slower, especially if your `Union` is quite big.

```py
{!.tmp_examples/model_config_smart_union_on.py!}
```
_(This script is complete, it should run "as is")_

!!! warning
Note that this option **does not support compound types yet** (e.g. differentiate `List[int]` and `List[str]`).
This option will be improved further once a strict mode is added in _pydantic_ and will probably be the default behaviour in v2!

```py
{!.tmp_examples/model_config_smart_union_on_edge_case.py!}
```
_(This script is complete, it should run "as is")_
5 changes: 2 additions & 3 deletions docs/usage/postponed_annotations.md
Expand Up @@ -45,9 +45,8 @@ Resolving this is beyond the call for *pydantic*: either remove the future impor

## Self-referencing Models

Data structures with self-referencing models are also supported, provided the function
`update_forward_refs()` is called once the model is created (you will be reminded
with a friendly error message if you forget).
Data structures with self-referencing models are also supported. Self-referencing fields will be automatically
resolved after model creation.

Within the model, you can refer to the not-yet-constructed model using a string:

Expand Down

0 comments on commit a5601ad

Please sign in to comment.