Skip to content

Commit

Permalink
Rename "container" attributes
Browse files Browse the repository at this point in the history
"container" is a misnomer
#1066 (review)
  • Loading branch information
sloria committed Jun 15, 2019
1 parent 10ef75f commit bff0ba2
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 68 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ Features:
using dateutil for parsing RFC dates (:pr:`1246`).
- Improve error messages for ``validate.Range``.

Other changes:

- *Backwards-incompatible*: Rename ``fields.List.container`` to ``fields.List.inner``,
``fields.Dict.key_container`` to ``fields.Dict.key_field``, and
``fields.Dict.value_container`` to ``fields.Dict.value_field``.

3.0.0rc7 (2019-06-15)
+++++++++++++++++++++

Expand Down
100 changes: 50 additions & 50 deletions src/marshmallow/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -570,33 +570,33 @@ class List(Field):
def __init__(self, cls_or_instance, **kwargs):
super().__init__(**kwargs)
try:
self.container = resolve_field_instance(cls_or_instance)
self.inner = resolve_field_instance(cls_or_instance)
except FieldInstanceResolutionError:
raise ValueError(
'The list elements must be a subclass or instance of '
'marshmallow.base.FieldABC.',
)
if isinstance(self.container, Nested):
self.only = self.container.only
self.exclude = self.container.exclude
if isinstance(self.inner, Nested):
self.only = self.inner.only
self.exclude = self.inner.exclude

def _bind_to_schema(self, field_name, schema):
super()._bind_to_schema(field_name, schema)
self.container = copy.deepcopy(self.container)
self.container.parent = self
self.container.name = field_name
if isinstance(self.container, Nested):
self.container.only = self.only
self.container.exclude = self.exclude
self.inner = copy.deepcopy(self.inner)
self.inner.parent = self
self.inner.name = field_name
if isinstance(self.inner, Nested):
self.inner.only = self.only
self.inner.exclude = self.exclude

def _serialize(self, value, attr, obj, **kwargs):
if value is None:
return None
if utils.is_collection(value):
return [
self.container._serialize(each, attr, obj, **kwargs) for each in value
self.inner._serialize(each, attr, obj, **kwargs) for each in value
]
return [self.container._serialize(value, attr, obj, **kwargs)]
return [self.inner._serialize(value, attr, obj, **kwargs)]

def _deserialize(self, value, attr, data, **kwargs):
if not utils.is_collection(value):
Expand All @@ -606,7 +606,7 @@ def _deserialize(self, value, attr, data, **kwargs):
errors = {}
for idx, each in enumerate(value):
try:
result.append(self.container.deserialize(each, **kwargs))
result.append(self.inner.deserialize(each, **kwargs))
except ValidationError as error:
if error.valid_data is not None:
result.append(error.valid_data)
Expand Down Expand Up @@ -661,11 +661,11 @@ def __init__(self, tuple_fields, *args, **kwargs):
def _bind_to_schema(self, field_name, schema):
super()._bind_to_schema(field_name, schema)
new_tuple_fields = []
for container in self.tuple_fields:
container = copy.deepcopy(container)
container.parent = self
container.name = field_name
new_tuple_fields.append(container)
for field in self.tuple_fields:
field = copy.deepcopy(field)
field.parent = self
field.name = field_name
new_tuple_fields.append(field)

self.tuple_fields = new_tuple_fields

Expand All @@ -674,8 +674,8 @@ def _serialize(self, value, attr, obj, **kwargs):
return None

return tuple(
container._serialize(each, attr, obj, **kwargs)
for container, each in zip(self.tuple_fields, value)
field._serialize(each, attr, obj, **kwargs)
for field, each in zip(self.tuple_fields, value)
)

def _deserialize(self, value, attr, data, **kwargs):
Expand All @@ -687,9 +687,9 @@ def _deserialize(self, value, attr, data, **kwargs):
result = []
errors = {}

for idx, (container, each) in enumerate(zip(self.tuple_fields, value)):
for idx, (field, each) in enumerate(zip(self.tuple_fields, value)):
try:
result.append(container.deserialize(each, **kwargs))
result.append(field.deserialize(each, **kwargs))
except ValidationError as error:
if error.valid_data is not None:
result.append(error.valid_data)
Expand Down Expand Up @@ -1275,70 +1275,70 @@ class Mapping(Field):
def __init__(self, keys=None, values=None, **kwargs):
super().__init__(**kwargs)
if keys is None:
self.key_container = None
self.key_field = None
else:
try:
self.key_container = resolve_field_instance(keys)
self.key_field = resolve_field_instance(keys)
except FieldInstanceResolutionError:
raise ValueError(
'"keys" must be a subclass or instance of '
'marshmallow.base.FieldABC.',
)

if values is None:
self.value_container = None
self.value_field = None
else:
try:
self.value_container = resolve_field_instance(values)
self.value_field = resolve_field_instance(values)
except FieldInstanceResolutionError:
raise ValueError(
'"values" must be a subclass or instance of '
'marshmallow.base.FieldABC.',
)
if isinstance(self.value_container, Nested):
self.only = self.value_container.only
self.exclude = self.value_container.exclude
if isinstance(self.value_field, Nested):
self.only = self.value_field.only
self.exclude = self.value_field.exclude

def _bind_to_schema(self, field_name, schema):
super()._bind_to_schema(field_name, schema)
if self.value_container:
self.value_container = copy.deepcopy(self.value_container)
self.value_container.parent = self
self.value_container.name = field_name
if isinstance(self.value_container, Nested):
self.value_container.only = self.only
self.value_container.exclude = self.exclude
if self.key_container:
self.key_container = copy.deepcopy(self.key_container)
self.key_container.parent = self
self.key_container.name = field_name
if self.value_field:
self.value_field = copy.deepcopy(self.value_field)
self.value_field.parent = self
self.value_field.name = field_name
if isinstance(self.value_field, Nested):
self.value_field.only = self.only
self.value_field.exclude = self.exclude
if self.key_field:
self.key_field = copy.deepcopy(self.key_field)
self.key_field.parent = self
self.key_field.name = field_name

def _serialize(self, value, attr, obj, **kwargs):
if value is None:
return None
if not self.value_container and not self.key_container:
if not self.value_field and not self.key_field:
return value
if not isinstance(value, _Mapping):
self.fail('invalid')

#  Serialize keys
if self.key_container is None:
if self.key_field is None:
keys = {k: k for k in value.keys()}
else:
keys = {
k: self.key_container._serialize(k, None, None, **kwargs)
k: self.key_field._serialize(k, None, None, **kwargs)
for k in value.keys()
}

#  Serialize values
result = self.mapping_type()
if self.value_container is None:
if self.value_field is None:
for k, v in value.items():
if k in keys:
result[keys[k]] = v
else:
for k, v in value.items():
result[keys[k]] = self.value_container._serialize(
result[keys[k]] = self.value_field._serialize(
v, None, None, **kwargs
)

Expand All @@ -1347,32 +1347,32 @@ def _serialize(self, value, attr, obj, **kwargs):
def _deserialize(self, value, attr, data, **kwargs):
if not isinstance(value, _Mapping):
self.fail('invalid')
if not self.value_container and not self.key_container:
if not self.value_field and not self.key_field:
return value

errors = collections.defaultdict(dict)

#  Deserialize keys
if self.key_container is None:
if self.key_field is None:
keys = {k: k for k in value.keys()}
else:
keys = {}
for key in value.keys():
try:
keys[key] = self.key_container.deserialize(key, **kwargs)
keys[key] = self.key_field.deserialize(key, **kwargs)
except ValidationError as error:
errors[key]['key'] = error.messages

#  Deserialize values
result = self.mapping_type()
if self.value_container is None:
if self.value_field is None:
for k, v in value.items():
if k in keys:
result[keys[k]] = v
else:
for key, val in value.items():
try:
deser_val = self.value_container.deserialize(val, **kwargs)
deser_val = self.value_field.deserialize(val, **kwargs)
except ValidationError as error:
errors[key]['value'] = error.messages
if error.valid_data is not None and key in keys:
Expand Down
36 changes: 18 additions & 18 deletions tests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,32 +122,32 @@ def test_unbound_field_root_returns_none(self):
assert inner_field.root is None

def test_list_field_inner_parent_and_name(self, schema):
assert schema.fields['bar'].container.parent == schema.fields['bar']
assert schema.fields['bar'].container.name == 'bar'
assert schema.fields['bar'].inner.parent == schema.fields['bar']
assert schema.fields['bar'].inner.name == 'bar'

def test_tuple_field_inner_parent_and_name(self, schema):
for container in schema.fields['baz'].tuple_fields:
assert container.parent == schema.fields['baz']
assert container.name == 'baz'
for field in schema.fields['baz'].tuple_fields:
assert field.parent == schema.fields['baz']
assert field.name == 'baz'

def test_simple_field_root(self, schema):
assert schema.fields['foo'].root == schema
assert schema.fields['bar'].root == schema

def test_list_field_inner_root(self, schema):
assert schema.fields['bar'].container.root == schema
assert schema.fields['bar'].inner.root == schema

def test_tuple_field_inner_root(self, schema):
for container in schema.fields['baz'].tuple_fields:
assert container.root == schema
for field in schema.fields['baz'].tuple_fields:
assert field.root == schema

def test_list_root_inheritance(self, schema):
class OtherSchema(TestParentAndName.MySchema):
pass

schema2 = OtherSchema()
assert schema.fields['bar'].container.root == schema
assert schema2.fields['bar'].container.root == schema2
assert schema.fields['bar'].inner.root == schema
assert schema2.fields['bar'].inner.root == schema2

def test_dict_root_inheritance(self):
class MySchema(Schema):
Expand All @@ -158,10 +158,10 @@ class OtherSchema(MySchema):

schema = MySchema()
schema2 = OtherSchema()
assert schema.fields['foo'].key_container.root == schema
assert schema.fields['foo'].value_container.root == schema
assert schema2.fields['foo'].key_container.root == schema2
assert schema2.fields['foo'].value_container.root == schema2
assert schema.fields['foo'].key_field.root == schema
assert schema.fields['foo'].value_field.root == schema
assert schema2.fields['foo'].key_field.root == schema2
assert schema2.fields['foo'].value_field.root == schema2


class TestMetadata:
Expand Down Expand Up @@ -258,7 +258,7 @@ class Family(Schema):
children = fields.List(fields.Nested(Child))

schema = Family(**{param: ['children.name']})
assert getattr(schema.fields['children'].container.schema, param) == {'name'}
assert getattr(schema.fields['children'].inner.schema, param) == {'name'}

@pytest.mark.parametrize(
('param', 'expected'),
Expand All @@ -275,7 +275,7 @@ class Family(Schema):
children = fields.List(fields.Nested(Child, **{param: ('name', 'surname')}))

schema = Family(**{param: ['children.name', 'children.age']})
assert getattr(schema.fields['children'].container, param) == expected
assert getattr(schema.fields['children'].inner, param) == expected

def test_list_nested_partial_propagated_to_nested(self):

Expand Down Expand Up @@ -366,7 +366,7 @@ class Family(Schema):
children = fields.Dict(values=fields.Nested(Child))

schema = Family(**{param: ['children.name']})
assert getattr(schema.fields['children'].value_container.schema, param) == {'name'}
assert getattr(schema.fields['children'].value_field.schema, param) == {'name'}

@pytest.mark.parametrize(
('param', 'expected'),
Expand All @@ -383,7 +383,7 @@ class Family(Schema):
children = fields.Dict(values=fields.Nested(Child, **{param: ('name', 'surname')}))

schema = Family(**{param: ['children.name', 'children.age']})
assert getattr(schema.fields['children'].value_container, param) == expected
assert getattr(schema.fields['children'].value_field, param) == expected

def test_dict_nested_partial_propagated_to_nested(self):

Expand Down

0 comments on commit bff0ba2

Please sign in to comment.