Skip to content

Commit

Permalink
Merge 59baa4e into 6ec9bf0
Browse files Browse the repository at this point in the history
  • Loading branch information
ss18 committed May 7, 2019
2 parents 6ec9bf0 + 59baa4e commit 3b1347d
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 8 deletions.
11 changes: 10 additions & 1 deletion .gitignore
Expand Up @@ -13,4 +13,13 @@ README.html
#*
.coverage
.pytest_cache
.eggs
.eggs

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
7 changes: 7 additions & 0 deletions pyrsistent/_field_common.py
Expand Up @@ -46,6 +46,13 @@ def check_type(destination_cls, field, name, value):
raise PTypeError(destination_cls, name, field.type, actual_type, message)


def is_type_cls(type_cls, field_type):
types = tuple(field_type)
if len(types) == 0:
return False
return issubclass(get_type(types[0]), type_cls)


class _PField(object):
__slots__ = ('type', 'invariant', 'initial', 'mandatory', '_factory', 'serializer')

Expand Down
19 changes: 12 additions & 7 deletions pyrsistent/_precord.py
@@ -1,7 +1,8 @@
import six
from pyrsistent._checked_types import CheckedType, _restore_pickle, InvariantException, store_invariants
from pyrsistent._field_common import (
set_fields, check_type, PFIELD_NO_INITIAL, serialize, check_global_invariants)
set_fields, check_type, is_type_cls, PFIELD_NO_INITIAL, serialize, check_global_invariants
)
from pyrsistent._pmap import PMap, pmap


Expand Down Expand Up @@ -39,14 +40,15 @@ def __new__(cls, **kwargs):
return super(PRecord, cls).__new__(cls, kwargs['_precord_size'], kwargs['_precord_buckets'])

factory_fields = kwargs.pop('_factory_fields', None)
ignore_extra = kwargs.pop('_ignore_extra', False)

initial_values = kwargs
if cls._precord_initial_values:
initial_values = dict((k, v() if callable(v) else v)
for k, v in cls._precord_initial_values.items())
initial_values.update(kwargs)

e = _PRecordEvolver(cls, pmap(), _factory_fields=factory_fields)
e = _PRecordEvolver(cls, pmap(), _factory_fields=factory_fields, _ignore_extra=ignore_extra)
for k, v in initial_values.items():
e[k] = v

Expand Down Expand Up @@ -91,7 +93,7 @@ def create(cls, kwargs, _factory_fields=None, ignore_extra=False):
if ignore_extra:
kwargs = {k: kwargs[k] for k in cls._precord_fields if k in kwargs}

return cls(_factory_fields=_factory_fields, **kwargs)
return cls(_factory_fields=_factory_fields, _ignore_extra=ignore_extra, **kwargs)

def __reduce__(self):
# Pickling support
Expand All @@ -106,14 +108,15 @@ def serialize(self, format=None):


class _PRecordEvolver(PMap._Evolver):
__slots__ = ('_destination_cls', '_invariant_error_codes', '_missing_fields', '_factory_fields')
__slots__ = ('_destination_cls', '_invariant_error_codes', '_missing_fields', '_factory_fields', '_ignore_extra')

def __init__(self, cls, original_pmap, _factory_fields=None):
def __init__(self, cls, original_pmap, _factory_fields=None, _ignore_extra=False):
super(_PRecordEvolver, self).__init__(original_pmap)
self._destination_cls = cls
self._invariant_error_codes = []
self._missing_fields = []
self._factory_fields = _factory_fields
self._ignore_extra = _ignore_extra

def __setitem__(self, key, original_value):
self.set(key, original_value)
Expand All @@ -123,7 +126,10 @@ def set(self, key, original_value):
if field:
if self._factory_fields is None or field in self._factory_fields:
try:
value = field.factory(original_value)
if is_type_cls(PRecord, field.type):
value = field.factory(original_value, ignore_extra=self._ignore_extra)
else:
value = field.factory(original_value)
except InvariantException as e:
self._invariant_error_codes += e.invariant_errors
self._missing_fields += e.missing_fields
Expand Down Expand Up @@ -161,4 +167,3 @@ def persistent(self):
check_global_invariants(result, cls._precord_invariants)

return result

12 changes: 12 additions & 0 deletions tests/class_test.py
Expand Up @@ -15,6 +15,10 @@ class Point(PClass):
z = field(type=int, initial=0)


class Hierarchy(PClass):
point = field(type=Point)


class TypedContainerObj(PClass):
map = pmap_field(str, str)
set = pset_field(str)
Expand All @@ -39,6 +43,14 @@ def test_create_ignore_extra_false():
_ = Point.create({'x': 5, 'y': 10, 'z': 15, 'a': 0})


@pytest.mark.skip(reason='Fix me. In PClass hierarchy ignore_extra s not propagating.')
def test_create_ignore_extra_true():
h = Hierarchy.create(
{'point': {'x': 5, 'y': 10, 'z': 15, 'extra_field_0': 'extra_data_0'}, 'extra_field_1': 'extra_data_1'},
ignore_extra=True)
assert isinstance(h, Hierarchy)


def test_evolve_pclass_instance():
p = Point(x=1, y=2)
p2 = p.set(x=p.x+2)
Expand Down
14 changes: 14 additions & 0 deletions tests/record_test.py
Expand Up @@ -14,6 +14,11 @@ class ARecord(PRecord):
y = field()


class Hierarchy(PRecord):
point1 = field(ARecord)
point2 = field(ARecord)


class RecordContainingContainers(PRecord):
map = pmap_field(str, str)
vec = pvector_field(str)
Expand All @@ -30,6 +35,15 @@ class Something(object):
class Another(object):
pass

def test_create_ignore_extra_true():
h = Hierarchy.create(
{'point1': {'x': 1, 'y': 'foo', 'extra_field_0': 'extra_data_0'},
'point2': {'x': 1, 'y': 'foo', 'extra_field_1': 'extra_data_1'},
'extra_field_2': 'extra_data_2',
}, ignore_extra=True
)
assert h

def test_create():
r = ARecord(x=1, y='foo')
assert r.x == 1
Expand Down

0 comments on commit 3b1347d

Please sign in to comment.