Skip to content

Commit

Permalink
Merge branch 'master' into f/discriminated-union
Browse files Browse the repository at this point in the history
  • Loading branch information
PrettyWood committed Feb 13, 2021
2 parents 798c0c8 + 13928e5 commit 4efcaa2
Show file tree
Hide file tree
Showing 90 changed files with 2,999 additions and 298 deletions.
11 changes: 11 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
blank_issues_enabled: true
contact_links:
- name: Question
url: https://github.com/samuelcolvin/pydantic/discussions/new
about: Ask a question about how to use pydantic using github discussions

- name: Feature Request
url: https://github.com/samuelcolvin/pydantic/discussions/new
about: >
If you think we should add a new feature to pydantic, please start a discussion, once it attracts
wider support, it can be migrated to an issue
36 changes: 0 additions & 36 deletions .github/ISSUE_TEMPLATE/feature_request.md

This file was deleted.

36 changes: 0 additions & 36 deletions .github/ISSUE_TEMPLATE/question.md

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dist/
.mypy_cache/
test.py
.coverage
.hypothesis
/htmlcov/
/benchmarks/*.json
/docs/.changelog.md
Expand Down
1 change: 1 addition & 0 deletions changes/1912-JSextonn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed issue causing KeyError to be raised when building schema from multiple `BaseModel` with the same names declared in separate classes.
2 changes: 2 additions & 0 deletions changes/1933-PrettyWood.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
**Breaking Change:** always validate only first sublevel items with `each_item`.
There were indeed some edge cases with some compound types where the validated items were the last sublevel ones.
1 change: 1 addition & 0 deletions changes/2061-layday.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
allow overwriting `ClassVar`s in sub-models without having to re-annotate them
1 change: 1 addition & 0 deletions changes/2064-art049.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add merged `json_encoders` inheritance
1 change: 1 addition & 0 deletions changes/2094-PrettyWood.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Handle properly fields of type `Callable` with a default value
1 change: 1 addition & 0 deletions changes/2097-Zac-HD.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a [Hypothesis](https://hypothesis.readthedocs.io/) plugin for easier [property-based testing](https://increment.com/testing/in-praise-of-property-based-testing/) with Pydantic's custom types - [usage details here](https://pydantic-docs.helpmanual.io/hypothesis_plugin/)
1 change: 1 addition & 0 deletions changes/2107-kozlek.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add the ability to customize settings sources (add / disable / change priority order).
1 change: 1 addition & 0 deletions changes/2134-tayoogunbiyi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
added `Config.anystr_lower` and `to_lower` kwarg to `constr` and `conbytes`.
1 change: 1 addition & 0 deletions changes/2147-JacobHayes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support `typing.Annotated` hints on model fields. A `Field` may now be set in the type hint with `Annotated[..., Field(...)`; all other annotations are ignored but still visible with `get_type_hints(..., include_extras=True)`.
1 change: 1 addition & 0 deletions changes/2175-davidolrik.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Allow non-existent secrets directory by only issuing a warning
1 change: 1 addition & 0 deletions changes/2195-sblack-usu.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add `allow_mutation` constraint to `Field`
1 change: 1 addition & 0 deletions changes/2198-Midnighter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a `FrozenSet[str]` type annotation to the `allowed_schemes` argument on the `strict_url` field type.
1 change: 1 addition & 0 deletions changes/2209-masalim2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Raise a user-friendly `TypeError` when a `root_validator` does not return a `dict` (e.g. `None`)
3 changes: 3 additions & 0 deletions changes/2216-PrettyWood.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Add support for `NamedTuple` and `TypedDict` types.
Those two types are now handled and validated when used inside `BaseModel` or _pydantic_ `dataclass`.
Two utils are also added `create_model_from_namedtuple` and `create_model_from_typeddict`.
1 change: 1 addition & 0 deletions changes/2220-PrettyWood.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Resolve forward refs for stdlib dataclasses converted into _pydantic_ ones
1 change: 1 addition & 0 deletions changes/2228-samuelcolvin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ensure cythonized functions are left untouched when creating models, based on #1944 by @kollmats
1 change: 1 addition & 0 deletions changes/2237-PrettyWood.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support custom root type (aka `__root__`) with `from_orm()`
1 change: 1 addition & 0 deletions changes/2238-PrettyWood.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support custom root type (aka `__root__`) when using `parse_obj()` with nested models
1 change: 1 addition & 0 deletions changes/2242-tayoogunbiyi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add documentation for con* type functions
2 changes: 2 additions & 0 deletions changes/2249-cybojenix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Prevent overriding positional arguments with keyword arguments in
`validate_arguments`, as per behaviour with native functions.
2 changes: 2 additions & 0 deletions changes/2251-cybojenix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix `validate_decorator` so `**kwargs` doesn't exclude values when the keyword
has the same name as the `*args` or `**kwargs` names.
1 change: 1 addition & 0 deletions changes/2262-maximberg.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support generating schema for Generic fields.
1 change: 1 addition & 0 deletions changes/2281-PrettyWood.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fix: keep order of fields with `BaseModel.construct()`
1 change: 1 addition & 0 deletions changes/2290-PrettyWood.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fix: update `__fields_set__` in `BaseModel.copy(update=…)`
1 change: 1 addition & 0 deletions changes/2306-hukkinj1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fix: `python_requires` metadata to require >=3.6.1
1 change: 1 addition & 0 deletions changes/2318-PrettyWood.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support empty tuple type
1 change: 1 addition & 0 deletions changes/2320-PrettyWood.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fix: allow `None` for type `Optional[conset / conlist]`
2 changes: 2 additions & 0 deletions changes/265-PrettyWood.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add `Config.copy_on_model_validation` flag. When set to `False`, _pydantic_ will keep models used as fields
untouched on validation instead of reconstructing (copying) them
36 changes: 26 additions & 10 deletions docs/build/exec_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import sys
import textwrap
import traceback
from pathlib import Path
from pathlib import Path, PosixPath
from typing import Any, List, Tuple
from unittest.mock import patch

Expand Down Expand Up @@ -62,6 +62,17 @@ def __call__(self, *args, file=None, flush=None):
self.statements.append((frame.f_lineno, s))


class MockPath(PosixPath):
def __new__(cls, name, *args, **kwargs):
if name == 'config.json':
return cls._from_parts(name, *args, **kwargs)
else:
return Path.__new__(cls, name, *args, **kwargs)

def read_text(self, *args, **kwargs) -> str:
return '{"foobar": "spam"}'


def build_print_lines(s: str, max_len_reduction: int = 0):
print_lines = []
max_len = MAX_LINE_LENGTH - 3 - max_len_reduction
Expand Down Expand Up @@ -133,7 +144,11 @@ def exec_examples():
errors = []
all_md = all_md_contents()
new_files = {}
os.environ.update({'my_auth_key': 'xxx', 'my_api_key': 'xxx'})
os.environ.update({
'my_auth_key': 'xxx',
'my_api_key': 'xxx',
'database_dsn': 'postgres://postgres@localhost:5432/env_db',
})

sys.path.append(str(EXAMPLES_DIR))
for file in sorted(EXAMPLES_DIR.iterdir()):
Expand Down Expand Up @@ -173,14 +188,15 @@ def error(desc: str):
del sys.modules[file.stem]
mp = MockPrint(file)
mod = None
with patch('builtins.print') as mock_print:
if print_intercept:
mock_print.side_effect = mp
try:
mod = importlib.import_module(file.stem)
except Exception:
tb = traceback.format_exception(*sys.exc_info())
error(''.join(e for e in tb if '/pydantic/docs/examples/' in e or not e.startswith(' File ')))
with patch('pathlib.Path', MockPath):
with patch('builtins.print') as patch_print:
if print_intercept:
patch_print.side_effect = mp
try:
mod = importlib.import_module(file.stem)
except Exception:
tb = traceback.format_exception(*sys.exc_info())
error(''.join(e for e in tb if '/pydantic/docs/examples/' in e or not e.startswith(' File ')))

if mod and not mod.__file__.startswith(str(EXAMPLES_DIR)):
error(f'module path "{mod.__file__}" not inside "{EXAMPLES_DIR}", name may shadow another module?')
Expand Down
20 changes: 20 additions & 0 deletions docs/examples/annotated_types_named_tuple.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from typing import NamedTuple

from pydantic import BaseModel, ValidationError


class Point(NamedTuple):
x: int
y: int


class Model(BaseModel):
p: Point


print(Model(p=('1', '2')))

try:
Model(p=('1.3', '2'))
except ValidationError as e:
print(e)
45 changes: 45 additions & 0 deletions docs/examples/annotated_types_typed_dict.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from typing import TypedDict

from pydantic import BaseModel, Extra, ValidationError


# `total=False` means keys are non-required
class UserIdentity(TypedDict, total=False):
name: str
surname: str


class User(TypedDict):
identity: UserIdentity
age: int


class Model(BaseModel):
u: User

class Config:
extra = Extra.forbid


print(Model(u={'identity': {'name': 'Smith', 'surname': 'John'}, 'age': '37'}))

print(Model(u={'identity': {'name': None, 'surname': 'John'}, 'age': '37'}))

print(Model(u={'identity': {}, 'age': '37'}))


try:
Model(u={'identity': {'name': ['Smith'], 'surname': 'John'}, 'age': '24'})
except ValidationError as e:
print(e)

try:
Model(
u={
'identity': {'name': 'Smith', 'surname': 'John'},
'age': '37',
'email': 'john.smith@me.com',
}
)
except ValidationError as e:
print(e)
24 changes: 24 additions & 0 deletions docs/examples/exporting_models_json_encoders_merge.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from datetime import datetime, timedelta
from pydantic import BaseModel
from pydantic.json import timedelta_isoformat


class BaseClassWithEncoders(BaseModel):
dt: datetime
diff: timedelta

class Config:
json_encoders = {
datetime: lambda v: v.timestamp()
}


class ChildClassWithEncoders(BaseClassWithEncoders):
class Config:
json_encoders = {
timedelta: timedelta_isoformat
}


m = ChildClassWithEncoders(dt=datetime(2032, 6, 1), diff=timedelta(hours=100))
print(m.json())
24 changes: 24 additions & 0 deletions docs/examples/hypothesis_property_based_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import typing
from hypothesis import given, strategies as st
from pydantic import BaseModel, EmailStr, PaymentCardNumber, PositiveFloat


class Model(BaseModel):
card: PaymentCardNumber
price: PositiveFloat
users: typing.List[EmailStr]


@given(st.builds(Model))
def test_property(instance):
# Hypothesis calls this test function many times with varied Models,
# so you can write a test that should pass given *any* instance.
assert 0 < instance.price
assert all('@' in email for email in instance.users)


@given(st.builds(Model, price=st.floats(100, 200)))
def test_with_discount(instance):
# This test shows how you can override specific fields,
# and let Hypothesis fill in any you don't care about.
assert 100 <= instance.price <= 200
14 changes: 14 additions & 0 deletions docs/examples/model_config_change_globally_custom.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from pydantic import BaseModel as PydanticBaseModel


class BaseModel(PydanticBaseModel):
class Config:
arbitrary_types_allowed = True


class MyClass:
"""A random class"""


class Model(BaseModel):
x: MyClass
21 changes: 21 additions & 0 deletions docs/examples/models_from_typeddict.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from typing import TypedDict

from pydantic import ValidationError, create_model_from_typeddict


class User(TypedDict):
name: str
id: int


class Config:
extra = 'forbid'


UserM = create_model_from_typeddict(User, __config__=Config)
print(repr(UserM(name=123, id='3')))

try:
UserM(name=123, id='3', other='no')
except ValidationError as e:
print(e)

0 comments on commit 4efcaa2

Please sign in to comment.