convert values to a function, fix #28 (#43)

This commit is contained in:
Samuel Colvin
2017-06-07 22:40:09 +01:00
committed by GitHub
parent 691b947576
commit ff3fa95eb0
7 changed files with 57 additions and 24 deletions
+2
View File
@@ -5,6 +5,8 @@ History
v0.2.0 (TBC)
............
* **breaking change**: ``values()`` on a model is now a method not a property,
takes ``include`` and ``exclude`` arguments
* allow annotation only fields to support mypy
* add pretty ``to_string(pretty=True)`` method for models
+1 -1
View File
@@ -37,7 +37,7 @@ m = Model(
email_address='Samuel Colvin <s@muelcolvin.com >',
email_and_name='Samuel Colvin <s@muelcolvin.com >',
)
print(m.values)
print(m.values())
"""
{
'cos_function': <built-in function cos>,
+1 -1
View File
@@ -17,5 +17,5 @@ class Spam(BaseModel):
m = Spam(foo={'count': 4}, bars=[{'apple': 'x1'}, {'apple': 'x2'}])
print(m)
# > Spam foo=<Foo count=4 size=None> bars=[<Bar apple='x1' banana='y'>, <Bar apple='x2' banana='y'>]
print(m.values)
print(m.values())
# {'foo': {'count': 4, 'size': None}, 'bars': [{'apple': 'x1', 'banana': 'y'}, {'apple': 'x2', 'banana': 'y'}]}
+15 -7
View File
@@ -1,5 +1,6 @@
from collections import OrderedDict
from types import FunctionType
from typing import Any, Dict, Set
from .exceptions import Error, Extra, Missing, ValidationError
from .fields import Field
@@ -96,7 +97,7 @@ class BaseModel(metaclass=MetaModel):
Config = BaseConfig
def __init__(self, **values):
self.__values__ = {}
self.__values__ = OrderedDict()
self.__errors__ = OrderedDict()
self._process_values(values)
@@ -111,9 +112,16 @@ class BaseModel(metaclass=MetaModel):
setattr(self, name, value)
self.__values__[name] = value
@property
def values(self):
return dict(self)
def values(self, *, include: Set[str]=None, exclude: Set[str]=set()) -> Dict[str, Any]:
"""
Get a dict of the values processed by the model, optionally specifying which fields to include or exclude.
This is NOT equivalent to the values() method on a dict.
"""
return {
k: v for k, v in self
if k not in exclude and (not include or k in include)
}
@property
def fields(self):
@@ -175,7 +183,7 @@ class BaseModel(metaclass=MetaModel):
@classmethod
def _get_value(cls, v):
if isinstance(v, BaseModel):
return v.values
return v.values()
elif isinstance(v, list):
return [cls._get_value(v_) for v_ in v]
elif isinstance(v, dict):
@@ -194,9 +202,9 @@ class BaseModel(metaclass=MetaModel):
def __eq__(self, other):
if isinstance(other, BaseModel):
return self.values == other.values
return self.values() == other.values()
else:
return self.values == other
return self.values() == other
def __repr__(self):
return f'<{self}>'
+28 -5
View File
@@ -180,7 +180,7 @@ class DictModel(BaseModel):
def test_dict_values():
assert DictModel(v={'foo': 1}).values == {'v': {'foo': 1}}
assert DictModel(v={'foo': 1}).values() == {'v': {'foo': 1}}
@pytest.mark.parametrize('value,result', [
@@ -269,7 +269,7 @@ def test_recursive_list():
assert "<MasterListModel v=[<SubModel name='testing' count=4>]>" == repr(m)
assert m.v[0].name == 'testing'
assert m.v[0].count == 4
assert m.values == {'v': [{'count': 4, 'name': 'testing'}]}
assert m.values() == {'v': [{'count': 4, 'name': 'testing'}]}
with pytest.raises(ValidationError) as exc_info:
MasterListModel(v=['x'])
@@ -356,9 +356,9 @@ def test_str_enum():
def test_any_dict():
class Model(BaseModel):
v: Dict[int, Any] = ...
assert Model(v={1: 'foobar'}).values == {'v': {1: 'foobar'}}
assert Model(v={123: 456}).values == {'v': {123: 456}}
assert Model(v={2: [1, 2, 3]}).values == {'v': {2: [1, 2, 3]}}
assert Model(v={1: 'foobar'}).values() == {'v': {1: 'foobar'}}
assert Model(v={123: 456}).values() == {'v': {123: 456}}
assert Model(v={2: [1, 2, 3]}).values() == {'v': {2: [1, 2, 3]}}
def test_infer_alias():
@@ -402,3 +402,26 @@ def test_annotation_config():
assert list(Model.__fields__.keys()) == ['b', 'a']
assert [f.alias for f in Model.__fields__.values()] == ['b', 'foobar']
assert Model(foobar='123').a == 123.0
def test_success_values_include():
class Model(BaseModel):
a: int = 1
b: int = 2
c: int = 3
m = Model()
assert m.values() == {'a': 1, 'b': 2, 'c': 3}
assert m.values(include={'a'}) == {'a': 1}
assert m.values(exclude={'a'}) == {'b': 2, 'c': 3}
assert m.values(include={'a', 'b'}, exclude={'a'}) == {'b': 2}
def test_values_order():
class Model(BaseModel):
a: int = 1
b: int = 2
c: int = 3
m = Model(c=30, b=20, a=10)
assert list(m) == [('a', 10), ('b', 20), ('c', 30)]
+7 -7
View File
@@ -244,19 +244,19 @@ def test_allow_extra():
class Config:
allow_extra = True
assert Model(a='10.2', b=12).values == {'a': 10.2, 'b': 12}
assert Model(a='10.2', b=12).values() == {'a': 10.2, 'b': 12}
def test_set_attr():
m = UltraSimpleModel(a=10.2)
assert m.values == {'a': 10.2, 'b': 10}
assert m.values() == {'a': 10.2, 'b': 10}
m.setattr('b', 20)
assert m.values == {'a': 10.2, 'b': 20}
assert m.values() == {'a': 10.2, 'b': 20}
def test_set_attr_invalid():
m = UltraSimpleModel(a=10.2)
assert m.values == {'a': 10.2, 'b': 10}
assert m.values() == {'a': 10.2, 'b': 10}
with pytest.raises(ValueError) as exc_info:
m.setattr('c', 20)
assert '"UltraSimpleModel" object has no field "c"' in str(exc_info)
@@ -280,9 +280,9 @@ def test_alias():
}
assert Model().a == 'foobar'
assert Model().values == {'a': 'foobar'}
assert Model().values() == {'a': 'foobar'}
assert Model(_a='different').a == 'different'
assert Model(_a='different').values == {'a': 'different'}
assert Model(_a='different').values() == {'a': 'different'}
def test_field_order():
@@ -303,7 +303,7 @@ def test_required():
b: int = 10
m = Model(a=10.2)
assert m.values == dict(a=10.2, b=10)
assert m.values() == dict(a=10.2, b=10)
with pytest.raises(ValidationError) as exc_info:
Model()
+3 -3
View File
@@ -148,7 +148,7 @@ def test_default_validators(field, value, result):
with pytest.raises(ValidationError):
CheckModel(**kwargs)
else:
assert CheckModel(**kwargs).values[field] == result
assert CheckModel(**kwargs).values()[field] == result
class DatetimeModel(BaseModel):
@@ -348,7 +348,7 @@ def test_tuple():
m = ListDictTupleModel(d=(1, 2, '3'))
assert m.a is None
assert m.d == (1, 2, '3')
assert m.values == {'a': None, 'b': None, 'c': None, 'd': (1, 2, '3')}
assert m.values() == {'a': None, 'b': None, 'c': None, 'd': (1, 2, '3')}
assert ListDictTupleModel(d='xyz').d == ('x', 'y', 'z')
assert ListDictTupleModel(d=(i**2 for i in range(5))).d == (0, 1, 4, 9, 16)
with pytest.raises(ValidationError) as exc_info:
@@ -376,5 +376,5 @@ def test_set():
m = SetModel(v=[1, 2, 3])
assert m.v == {1, 2, 3}
assert m.values == {'v': {1, 2, 3}}
assert m.values() == {'v': {1, 2, 3}}
assert SetModel(v={'a', 'b', 'c'}).v == {'a', 'b', 'c'}