Skip to content

Commit

Permalink
remove DeprecationWarnings from v1 release & fix coverage (#2415)
Browse files Browse the repository at this point in the history
* remove DeprecationWarnings from v1 release

* coverage on unpickling Undefined private attributes

* coverage on undefined in copy, allow Undefined to be pickled unchanged

* fix coverage of model._iter()
  • Loading branch information
samuelcolvin committed Feb 26, 2021
1 parent 8f0980e commit 2ee6811
Show file tree
Hide file tree
Showing 11 changed files with 47 additions and 181 deletions.
76 changes: 0 additions & 76 deletions docs/version_1_release_notes.md

This file was deleted.

1 change: 0 additions & 1 deletion mkdocs.yml
Expand Up @@ -28,7 +28,6 @@ extra_javascript:
nav:
- Overview: index.md
- install.md
- 'Version 1 release notes': version_1_release_notes.md
- Usage:
- usage/models.md
- 'Field Types': usage/types.md
Expand Down
3 changes: 1 addition & 2 deletions pydantic/__init__.py
Expand Up @@ -6,7 +6,7 @@
from .env_settings import BaseSettings
from .error_wrappers import ValidationError
from .errors import *
from .fields import Field, PrivateAttr, Required, Schema
from .fields import Field, PrivateAttr, Required
from .main import *
from .networks import *
from .parse import Protocol
Expand Down Expand Up @@ -34,7 +34,6 @@
# fields
'Field',
'Required',
'Schema',
# main
'BaseConfig',
'BaseModel',
Expand Down
9 changes: 3 additions & 6 deletions pydantic/fields.py
@@ -1,4 +1,3 @@
import warnings
from collections import defaultdict, deque
from collections.abc import Iterable as CollectionsIterable
from typing import (
Expand Down Expand Up @@ -59,6 +58,9 @@ def __repr__(self) -> str:
def __copy__(self: T) -> T:
return self

def __reduce__(self) -> str:
return 'Undefined'

def __deepcopy__(self: T, _: Any) -> T:
return self

Expand Down Expand Up @@ -233,11 +235,6 @@ def Field(
return field_info


def Schema(default: Any, **kwargs: Any) -> Any:
warnings.warn('`Schema` is deprecated, use `Field` instead', DeprecationWarning)
return Field(default, **kwargs)


# used to be an enum but changed to int's for small performance improvement as less access overhead
SHAPE_SINGLETON = 1
SHAPE_LIST = 2
Expand Down
38 changes: 6 additions & 32 deletions pydantic/main.py
Expand Up @@ -195,21 +195,6 @@ def prepare_config(config: Type[BaseConfig], cls_name: str) -> None:
except ValueError:
raise ValueError(f'"{cls_name}": {config.extra} is not a valid value for "extra"')

if hasattr(config, 'allow_population_by_alias'):
warnings.warn(
f'{cls_name}: "allow_population_by_alias" is deprecated and replaced by "allow_population_by_field_name"',
DeprecationWarning,
)
config.allow_population_by_field_name = config.allow_population_by_alias # type: ignore

if hasattr(config, 'case_insensitive') and any('BaseSettings.Config' in c.__qualname__ for c in config.__mro__):
warnings.warn(
f'{cls_name}: "case_insensitive" is deprecated on BaseSettings config and replaced by '
f'"case_sensitive" (default False)',
DeprecationWarning,
)
config.case_sensitive = not config.case_insensitive # type: ignore


def validate_custom_root_type(fields: Dict[str, ModelField]) -> None:
if len(fields) > 1:
Expand Down Expand Up @@ -466,18 +451,18 @@ def __setattr__(self, name, value): # noqa: C901 (ignore complexity)
self.__fields_set__.add(name)

def __getstate__(self) -> 'DictAny':
private_attrs = ((k, getattr(self, k, Undefined)) for k in self.__private_attributes__)
return {
'__dict__': self.__dict__,
'__fields_set__': self.__fields_set__,
'__private_attribute_values__': {k: getattr(self, k, Undefined) for k in self.__private_attributes__},
'__private_attribute_values__': {k: v for k, v in private_attrs if v is not Undefined},
}

def __setstate__(self, state: 'DictAny') -> None:
object_setattr(self, '__dict__', state['__dict__'])
object_setattr(self, '__fields_set__', state['__fields_set__'])
for name, value in state.get('__private_attribute_values__', {}).items():
if value is not Undefined:
object_setattr(self, name, value)
object_setattr(self, name, value)

def _init_private_attributes(self) -> None:
for name, private_attr in self.__private_attributes__.items():
Expand Down Expand Up @@ -859,14 +844,17 @@ def _iter(
for field_key, v in self.__dict__.items():
if (allowed_keys is not None and field_key not in allowed_keys) or (exclude_none and v is None):
continue

if exclude_defaults:
model_field = self.__fields__.get(field_key)
if not getattr(model_field, 'required', True) and getattr(model_field, 'default', _missing) == v:
continue

if by_alias and field_key in self.__fields__:
dict_key = self.__fields__[field_key].alias
else:
dict_key = field_key

if to_dict or value_include or value_exclude:
v = self._get_value(
v,
Expand Down Expand Up @@ -922,20 +910,6 @@ def __eq__(self, other: Any) -> bool:
def __repr_args__(self) -> 'ReprArgs':
return self.__dict__.items() # type: ignore

@property
def fields(self) -> Dict[str, ModelField]:
warnings.warn('`fields` attribute is deprecated, use `__fields__` instead', DeprecationWarning)
return self.__fields__

def to_string(self, pretty: bool = False) -> str:
warnings.warn('`model.to_string()` method is deprecated, use `str(model)` instead', DeprecationWarning)
return str(self)

@property
def __values__(self) -> 'DictStrAny':
warnings.warn('`__values__` attribute is deprecated, use `__dict__` instead', DeprecationWarning)
return self.__dict__


_is_base_model_class_defined = True

Expand Down
16 changes: 0 additions & 16 deletions tests/test_aliases.py
Expand Up @@ -161,22 +161,6 @@ class Config:
]


def test_population_by_alias():
with pytest.warns(DeprecationWarning, match='"allow_population_by_alias" is deprecated and replaced by'):

class Model(BaseModel):
a: str

class Config:
allow_population_by_alias = True
fields = {'a': {'alias': '_a'}}

assert Model.__config__.allow_population_by_field_name is True
assert Model(a='different').a == 'different'
assert Model(a='different').dict() == {'a': 'different'}
assert Model(a='different').dict(by_alias=True) == {'_a': 'different'}


def test_alias_child_precedence():
class Parent(BaseModel):
x: int
Expand Down
21 changes: 21 additions & 0 deletions tests/test_construction.py
Expand Up @@ -4,6 +4,7 @@
import pytest

from pydantic import BaseModel, Field, PrivateAttr
from pydantic.fields import Undefined


class Model(BaseModel):
Expand Down Expand Up @@ -253,6 +254,26 @@ def test_recursive_pickle():
assert m.__foo__ == m2.__foo__


def test_pickle_undefined():
m = ModelTwo(a=24, d=Model(a='123.45'))
m2 = pickle.loads(pickle.dumps(m))
assert m2.__foo__ == {'private'}

m.__foo__ = Undefined
m3 = pickle.loads(pickle.dumps(m))
assert not hasattr(m3, '__foo__')


def test_copy_undefined():
m = ModelTwo(a=24, d=Model(a='123.45'))
m2 = m.copy()
assert m2.__foo__ == {'private'}

m.__foo__ = Undefined
m3 = m.copy()
assert not hasattr(m3, '__foo__')


def test_immutable_copy_with_allow_mutation():
class Model(BaseModel):
a: int
Expand Down
39 changes: 9 additions & 30 deletions tests/test_edge_cases.py
Expand Up @@ -19,7 +19,7 @@
validate_model,
validator,
)
from pydantic.fields import Field, Schema
from pydantic.fields import Field

try:
import cython
Expand Down Expand Up @@ -1107,16 +1107,6 @@ class TopModel(model):
assert m.nest.modified_number == 1


def test_values_attr_deprecation():
class Model(BaseModel):
foo: int
bar: str

m = Model(foo=4, bar='baz')
with pytest.warns(DeprecationWarning, match='`__values__` attribute is deprecated, use `__dict__` instead'):
assert m.__values__ == m.__dict__


def test_init_inspection():
class Foobar(BaseModel):
x: int
Expand Down Expand Up @@ -1219,25 +1209,6 @@ def check_a(cls, v):
assert Model(a=12).a == 12


def test_scheme_deprecated():

with pytest.warns(DeprecationWarning, match='`Schema` is deprecated, use `Field` instead'):

class Model(BaseModel):
foo: int = Schema(4)


def test_fields_deprecated():
class Model(BaseModel):
v: str = 'x'

with pytest.warns(DeprecationWarning, match='`fields` attribute is deprecated, use `__fields__` instead'):
assert Model().fields.keys() == {'v'}

assert Model().__fields__.keys() == {'v'}
assert Model.__fields__.keys() == {'v'}


def test_optional_field_constraints():
class MyModel(BaseModel):
my_int: Optional[int] = Field(..., ge=3)
Expand Down Expand Up @@ -1793,3 +1764,11 @@ class User(BaseModel):
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
assert module.User(id=12).dict() == {'id': 12, 'name': 'Jane Doe'}


def test_iter_coverage():
class MyModel(BaseModel):
x: int = 1
y: str = 'a'

assert list(MyModel()._iter(by_alias=True)) == [('x', 1), ('y', 'a')]
3 changes: 1 addition & 2 deletions tests/test_main.py
Expand Up @@ -62,8 +62,7 @@ def test_ultra_simple_repr():
assert dict(m) == {'a': 10.2, 'b': 10}
assert m.dict() == {'a': 10.2, 'b': 10}
assert m.json() == '{"a": 10.2, "b": 10}'
with pytest.raises(DeprecationWarning, match=r'`model.to_string\(\)` method is deprecated'):
assert m.to_string() == 'a=10.2 b=10'
assert str(m) == 'a=10.2 b=10'


def test_default_factory_field():
Expand Down
16 changes: 0 additions & 16 deletions tests/test_settings.py
Expand Up @@ -394,22 +394,6 @@ class Config:
assert exc_info.value.errors() == [{'loc': ('foo',), 'msg': 'field required', 'type': 'value_error.missing'}]


def test_case_insensitive(monkeypatch):
class Settings1(BaseSettings):
foo: str

with pytest.warns(DeprecationWarning, match='Settings2: "case_insensitive" is deprecated on BaseSettings'):

class Settings2(BaseSettings):
foo: str

class Config:
case_insensitive = False

assert Settings1.__config__.case_sensitive is False
assert Settings2.__config__.case_sensitive is True


def test_nested_dataclass(env):
@dataclasses.dataclass
class MyDataclass:
Expand Down
6 changes: 6 additions & 0 deletions tests/test_utils.py
@@ -1,5 +1,6 @@
import collections.abc
import os
import pickle
import re
import string
import sys
Expand Down Expand Up @@ -499,3 +500,8 @@ def test_all_identical():
assert (
all_identical([a, [b], b], [a, [b], b]) is False
), 'New list objects are different objects and should therefor not be identical.'


def test_undefined_pickle():
undefined2 = pickle.loads(pickle.dumps(Undefined))
assert undefined2 is Undefined

0 comments on commit 2ee6811

Please sign in to comment.