123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878 |
- import pickle
- import datetime
- import pytest
- import uuid
- from pyrsistent import (
- PRecord, field, InvariantException, ny, pset, PSet, CheckedPVector,
- PTypeError, pset_field, pvector_field, pmap_field, pmap, PMap,
- pvector, PVector, v, m)
- class ARecord(PRecord):
- x = field(type=(int, float))
- y = field()
- class Hierarchy(PRecord):
- point1 = field(ARecord)
- point2 = field(ARecord)
- points = pvector_field(ARecord)
- class RecordContainingContainers(PRecord):
- map = pmap_field(str, str)
- vec = pvector_field(str)
- set = pset_field(str)
- class UniqueThing(PRecord):
- id = field(type=uuid.UUID, factory=uuid.UUID)
- class Something(object):
- pass
- 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_ignore_extra_true_sequence_hierarchy():
- 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'},
- 'points': [{'x': 1, 'y': 'foo', 'extra_field_2': 'extra_data_2'},
- {'x': 1, 'y': 'foo', 'extra_field_3': 'extra_data_3'}],
- 'extra_field____': 'extra_data_2',
- }, ignore_extra=True
- )
- assert h
- def test_ignore_extra_for_pvector_field():
- class HierarchyA(PRecord):
- points = pvector_field(ARecord, optional=False)
- class HierarchyB(PRecord):
- points = pvector_field(ARecord, optional=True)
- point_object = {'x': 1, 'y': 'foo', 'extra_field': 69}
- h = HierarchyA.create({'points': [point_object]}, ignore_extra=True)
- assert h
- h = HierarchyB.create({'points': [point_object]}, ignore_extra=True)
- assert h
- def test_create():
- r = ARecord(x=1, y='foo')
- assert r.x == 1
- assert r.y == 'foo'
- assert isinstance(r, ARecord)
- def test_create_ignore_extra():
- r = ARecord.create({'x': 1, 'y': 'foo', 'z': None}, ignore_extra=True)
- assert r.x == 1
- assert r.y == 'foo'
- assert isinstance(r, ARecord)
- def test_create_ignore_extra_false():
- with pytest.raises(AttributeError):
- _ = ARecord.create({'x': 1, 'y': 'foo', 'z': None})
- def test_correct_assignment():
- r = ARecord(x=1, y='foo')
- r2 = r.set('x', 2.0)
- r3 = r2.set('y', 'bar')
- assert r2 == {'x': 2.0, 'y': 'foo'}
- assert r3 == {'x': 2.0, 'y': 'bar'}
- assert isinstance(r3, ARecord)
- def test_direct_assignment_not_possible():
- with pytest.raises(AttributeError):
- ARecord().x = 1
- def test_cannot_assign_undeclared_fields():
- with pytest.raises(AttributeError):
- ARecord().set('z', 5)
- def test_cannot_assign_wrong_type_to_fields():
- try:
- ARecord().set('x', 'foo')
- assert False
- except PTypeError as e:
- assert e.source_class == ARecord
- assert e.field == 'x'
- assert e.expected_types == set([int, float])
- assert e.actual_type is type('foo')
- def test_cannot_construct_with_undeclared_fields():
- with pytest.raises(AttributeError):
- ARecord(z=5)
- def test_cannot_construct_with_fields_of_wrong_type():
- with pytest.raises(TypeError):
- ARecord(x='foo')
- def test_support_record_inheritance():
- class BRecord(ARecord):
- z = field()
- r = BRecord(x=1, y='foo', z='bar')
- assert isinstance(r, BRecord)
- assert isinstance(r, ARecord)
- assert r == {'x': 1, 'y': 'foo', 'z': 'bar'}
- def test_single_type_spec():
- class A(PRecord):
- x = field(type=int)
- r = A(x=1)
- assert r.x == 1
- with pytest.raises(TypeError):
- r.set('x', 'foo')
- def test_remove():
- r = ARecord(x=1, y='foo')
- r2 = r.remove('y')
- assert isinstance(r2, ARecord)
- assert r2 == {'x': 1}
- def test_remove_non_existing_member():
- r = ARecord(x=1, y='foo')
- with pytest.raises(KeyError):
- r.remove('z')
- def test_field_invariant_must_hold():
- class BRecord(PRecord):
- x = field(invariant=lambda x: (x > 1, 'x too small'))
- y = field(mandatory=True)
- try:
- BRecord(x=1)
- assert False
- except InvariantException as e:
- assert e.invariant_errors == ('x too small',)
- assert e.missing_fields == ('BRecord.y',)
- def test_global_invariant_must_hold():
- class BRecord(PRecord):
- __invariant__ = lambda r: (r.x <= r.y, 'y smaller than x')
- x = field()
- y = field()
- BRecord(x=1, y=2)
- try:
- BRecord(x=2, y=1)
- assert False
- except InvariantException as e:
- assert e.invariant_errors == ('y smaller than x',)
- assert e.missing_fields == ()
- def test_set_multiple_fields():
- a = ARecord(x=1, y='foo')
- b = a.set(x=2, y='bar')
- assert b == {'x': 2, 'y': 'bar'}
- def test_initial_value():
- class BRecord(PRecord):
- x = field(initial=1)
- y = field(initial=2)
- a = BRecord()
- assert a.x == 1
- assert a.y == 2
- def test_enum_field():
- try:
- from enum import Enum
- except ImportError:
- return # Enum not supported in this environment
- class ExampleEnum(Enum):
- x = 1
- y = 2
- class RecordContainingEnum(PRecord):
- enum_field = field(type=ExampleEnum)
- r = RecordContainingEnum(enum_field=ExampleEnum.x)
- assert r.enum_field == ExampleEnum.x
- def test_type_specification_must_be_a_type():
- with pytest.raises(TypeError):
- class BRecord(PRecord):
- x = field(type=1)
- def test_initial_must_be_of_correct_type():
- with pytest.raises(TypeError):
- class BRecord(PRecord):
- x = field(type=int, initial='foo')
- def test_invariant_must_be_callable():
- with pytest.raises(TypeError):
- class BRecord(PRecord):
- x = field(invariant='foo') # type: ignore
- def test_global_invariants_are_inherited():
- class BRecord(PRecord):
- __invariant__ = lambda r: (r.x % r.y == 0, 'modulo')
- x = field()
- y = field()
- class CRecord(BRecord):
- __invariant__ = lambda r: (r.x > r.y, 'size')
- try:
- CRecord(x=5, y=3)
- assert False
- except InvariantException as e:
- assert e.invariant_errors == ('modulo',)
- def test_global_invariants_must_be_callable():
- with pytest.raises(TypeError):
- class CRecord(PRecord):
- __invariant__ = 1
- def test_repr():
- r = ARecord(x=1, y=2)
- assert repr(r) == 'ARecord(x=1, y=2)' or repr(r) == 'ARecord(y=2, x=1)'
- def test_factory():
- class BRecord(PRecord):
- x = field(type=int, factory=int)
- assert BRecord(x=2.5) == {'x': 2}
- def test_factory_must_be_callable():
- with pytest.raises(TypeError):
- class BRecord(PRecord):
- x = field(type=int, factory=1) # type: ignore
- def test_nested_record_construction():
- class BRecord(PRecord):
- x = field(int, factory=int)
- class CRecord(PRecord):
- a = field()
- b = field(type=BRecord)
- r = CRecord.create({'a': 'foo', 'b': {'x': '5'}})
- assert isinstance(r, CRecord)
- assert isinstance(r.b, BRecord)
- assert r == {'a': 'foo', 'b': {'x': 5}}
- def test_pickling():
- x = ARecord(x=2.0, y='bar')
- y = pickle.loads(pickle.dumps(x, -1))
- assert x == y
- assert isinstance(y, ARecord)
- def test_supports_pickling_with_typed_container_fields():
- obj = RecordContainingContainers(
- map={'foo': 'bar'}, set=['hello', 'there'], vec=['a', 'b'])
- obj2 = pickle.loads(pickle.dumps(obj))
- assert obj == obj2
- def test_all_invariant_errors_reported():
- class BRecord(PRecord):
- x = field(factory=int, invariant=lambda x: (x >= 0, 'x negative'))
- y = field(mandatory=True)
- class CRecord(PRecord):
- a = field(invariant=lambda x: (x != 0, 'a zero'))
- b = field(type=BRecord)
- try:
- CRecord.create({'a': 0, 'b': {'x': -5}})
- assert False
- except InvariantException as e:
- assert set(e.invariant_errors) == set(['x negative', 'a zero'])
- assert e.missing_fields == ('BRecord.y',)
- def test_precord_factory_method_is_idempotent():
- class BRecord(PRecord):
- x = field()
- y = field()
- r = BRecord(x=1, y=2)
- assert BRecord.create(r) is r
- def test_serialize():
- class BRecord(PRecord):
- d = field(type=datetime.date,
- factory=lambda d: datetime.datetime.strptime(d, "%d%m%Y").date(),
- serializer=lambda format, d: d.strftime('%Y-%m-%d') if format == 'ISO' else d.strftime('%d%m%Y'))
- assert BRecord(d='14012015').serialize('ISO') == {'d': '2015-01-14'}
- assert BRecord(d='14012015').serialize('other') == {'d': '14012015'}
- def test_nested_serialize():
- class BRecord(PRecord):
- d = field(serializer=lambda format, d: format)
- class CRecord(PRecord):
- b = field()
- serialized = CRecord(b=BRecord(d='foo')).serialize('bar')
- assert serialized == {'b': {'d': 'bar'}}
- assert isinstance(serialized, dict)
- def test_serializer_must_be_callable():
- with pytest.raises(TypeError):
- class CRecord(PRecord):
- x = field(serializer=1) # type: ignore
- def test_transform_without_update_returns_same_precord():
- r = ARecord(x=2.0, y='bar')
- assert r.transform([ny], lambda x: x) is r
- class Application(PRecord):
- name = field(type=str)
- image = field(type=str)
- class ApplicationVector(CheckedPVector):
- __type__ = Application
- class Node(PRecord):
- applications = field(type=ApplicationVector)
- def test_nested_create_serialize():
- node = Node(applications=[Application(name='myapp', image='myimage'),
- Application(name='b', image='c')])
- node2 = Node.create({'applications': [{'name': 'myapp', 'image': 'myimage'},
- {'name': 'b', 'image': 'c'}]})
- assert node == node2
- serialized = node.serialize()
- restored = Node.create(serialized)
- assert restored == node
- def test_pset_field_initial_value():
- """
- ``pset_field`` results in initial value that is empty.
- """
- class Record(PRecord):
- value = pset_field(int)
- assert Record() == Record(value=[])
- def test_pset_field_custom_initial():
- """
- A custom initial value can be passed in.
- """
- class Record(PRecord):
- value = pset_field(int, initial=(1, 2))
- assert Record() == Record(value=[1, 2])
- def test_pset_field_factory():
- """
- ``pset_field`` has a factory that creates a ``PSet``.
- """
- class Record(PRecord):
- value = pset_field(int)
- record = Record(value=[1, 2])
- assert isinstance(record.value, PSet)
- def test_pset_field_checked_set():
- """
- ``pset_field`` results in a set that enforces its type.
- """
- class Record(PRecord):
- value = pset_field(int)
- record = Record(value=[1, 2])
- with pytest.raises(TypeError):
- record.value.add("hello") # type: ignore
- def test_pset_field_checked_vector_multiple_types():
- """
- ``pset_field`` results in a vector that enforces its types.
- """
- class Record(PRecord):
- value = pset_field((int, str))
- record = Record(value=[1, 2, "hello"])
- with pytest.raises(TypeError):
- record.value.add(object())
- def test_pset_field_type():
- """
- ``pset_field`` enforces its type.
- """
- class Record(PRecord):
- value = pset_field(int)
- record = Record()
- with pytest.raises(TypeError):
- record.set("value", None)
- def test_pset_field_mandatory():
- """
- ``pset_field`` is a mandatory field.
- """
- class Record(PRecord):
- value = pset_field(int)
- record = Record(value=[1])
- with pytest.raises(InvariantException):
- record.remove("value")
- def test_pset_field_default_non_optional():
- """
- By default ``pset_field`` is non-optional, i.e. does not allow
- ``None``.
- """
- class Record(PRecord):
- value = pset_field(int)
- with pytest.raises(TypeError):
- Record(value=None)
- def test_pset_field_explicit_non_optional():
- """
- If ``optional`` argument is ``False`` then ``pset_field`` is
- non-optional, i.e. does not allow ``None``.
- """
- class Record(PRecord):
- value = pset_field(int, optional=False)
- with pytest.raises(TypeError):
- Record(value=None)
- def test_pset_field_optional():
- """
- If ``optional`` argument is true, ``None`` is acceptable alternative
- to a set.
- """
- class Record(PRecord):
- value = pset_field(int, optional=True)
- assert ((Record(value=[1, 2]).value, Record(value=None).value) ==
- (pset([1, 2]), None))
- def test_pset_field_name():
- """
- The created set class name is based on the type of items in the set.
- """
- class Record(PRecord):
- value = pset_field(Something)
- value2 = pset_field(int)
- assert ((Record().value.__class__.__name__,
- Record().value2.__class__.__name__) ==
- ("SomethingPSet", "IntPSet"))
- def test_pset_multiple_types_field_name():
- """
- The created set class name is based on the multiple given types of
- items in the set.
- """
- class Record(PRecord):
- value = pset_field((Something, int))
- assert (Record().value.__class__.__name__ ==
- "SomethingIntPSet")
- def test_pset_field_name_string_type():
- """
- The created set class name is based on the type of items specified by name
- """
- class Record(PRecord):
- value = pset_field("record_test.Something")
- assert Record().value.__class__.__name__ == "SomethingPSet"
- def test_pset_multiple_string_types_field_name():
- """
- The created set class name is based on the multiple given types of
- items in the set specified by name
- """
- class Record(PRecord):
- value = pset_field(("record_test.Something", "record_test.Another"))
- assert Record().value.__class__.__name__ == "SomethingAnotherPSet"
- def test_pvector_field_initial_value():
- """
- ``pvector_field`` results in initial value that is empty.
- """
- class Record(PRecord):
- value = pvector_field(int)
- assert Record() == Record(value=[])
- def test_pvector_field_custom_initial():
- """
- A custom initial value can be passed in.
- """
- class Record(PRecord):
- value = pvector_field(int, initial=(1, 2))
- assert Record() == Record(value=[1, 2])
- def test_pvector_field_factory():
- """
- ``pvector_field`` has a factory that creates a ``PVector``.
- """
- class Record(PRecord):
- value = pvector_field(int)
- record = Record(value=[1, 2])
- assert isinstance(record.value, PVector)
- def test_pvector_field_checked_vector():
- """
- ``pvector_field`` results in a vector that enforces its type.
- """
- class Record(PRecord):
- value = pvector_field(int)
- record = Record(value=[1, 2])
- with pytest.raises(TypeError):
- record.value.append("hello") # type: ignore
- def test_pvector_field_checked_vector_multiple_types():
- """
- ``pvector_field`` results in a vector that enforces its types.
- """
- class Record(PRecord):
- value = pvector_field((int, str))
- record = Record(value=[1, 2, "hello"])
- with pytest.raises(TypeError):
- record.value.append(object())
- def test_pvector_field_type():
- """
- ``pvector_field`` enforces its type.
- """
- class Record(PRecord):
- value = pvector_field(int)
- record = Record()
- with pytest.raises(TypeError):
- record.set("value", None)
- def test_pvector_field_mandatory():
- """
- ``pvector_field`` is a mandatory field.
- """
- class Record(PRecord):
- value = pvector_field(int)
- record = Record(value=[1])
- with pytest.raises(InvariantException):
- record.remove("value")
- def test_pvector_field_default_non_optional():
- """
- By default ``pvector_field`` is non-optional, i.e. does not allow
- ``None``.
- """
- class Record(PRecord):
- value = pvector_field(int)
- with pytest.raises(TypeError):
- Record(value=None)
- def test_pvector_field_explicit_non_optional():
- """
- If ``optional`` argument is ``False`` then ``pvector_field`` is
- non-optional, i.e. does not allow ``None``.
- """
- class Record(PRecord):
- value = pvector_field(int, optional=False)
- with pytest.raises(TypeError):
- Record(value=None)
- def test_pvector_field_optional():
- """
- If ``optional`` argument is true, ``None`` is acceptable alternative
- to a sequence.
- """
- class Record(PRecord):
- value = pvector_field(int, optional=True)
- assert ((Record(value=[1, 2]).value, Record(value=None).value) ==
- (pvector([1, 2]), None))
- def test_pvector_field_name():
- """
- The created set class name is based on the type of items in the set.
- """
- class Record(PRecord):
- value = pvector_field(Something)
- value2 = pvector_field(int)
- assert ((Record().value.__class__.__name__,
- Record().value2.__class__.__name__) ==
- ("SomethingPVector", "IntPVector"))
- def test_pvector_multiple_types_field_name():
- """
- The created vector class name is based on the multiple given types of
- items in the vector.
- """
- class Record(PRecord):
- value = pvector_field((Something, int))
- assert (Record().value.__class__.__name__ ==
- "SomethingIntPVector")
- def test_pvector_field_name_string_type():
- """
- The created set class name is based on the type of items in the set
- specified by name.
- """
- class Record(PRecord):
- value = pvector_field("record_test.Something")
- assert Record().value.__class__.__name__ == "SomethingPVector"
- def test_pvector_multiple_string_types_field_name():
- """
- The created vector class name is based on the multiple given types of
- items in the vector.
- """
- class Record(PRecord):
- value = pvector_field(("record_test.Something", "record_test.Another"))
- assert Record().value.__class__.__name__ == "SomethingAnotherPVector"
- def test_pvector_field_create_from_nested_serialized_data():
- class Foo(PRecord):
- foo = field(type=str)
- class Bar(PRecord):
- bar = pvector_field(Foo)
- data = Bar(bar=v(Foo(foo="foo")))
- Bar.create(data.serialize()) == data
- def test_pmap_field_initial_value():
- """
- ``pmap_field`` results in initial value that is empty.
- """
- class Record(PRecord):
- value = pmap_field(int, int)
- assert Record() == Record(value={})
- def test_pmap_field_factory():
- """
- ``pmap_field`` has a factory that creates a ``PMap``.
- """
- class Record(PRecord):
- value = pmap_field(int, int)
- record = Record(value={1: 1234})
- assert isinstance(record.value, PMap)
- def test_pmap_field_checked_map_key():
- """
- ``pmap_field`` results in a map that enforces its key type.
- """
- class Record(PRecord):
- value = pmap_field(int, type(None))
- record = Record(value={1: None})
- with pytest.raises(TypeError):
- record.value.set("hello", None) # type: ignore
- def test_pmap_field_checked_map_value():
- """
- ``pmap_field`` results in a map that enforces its value type.
- """
- class Record(PRecord):
- value = pmap_field(int, type(None))
- record = Record(value={1: None})
- with pytest.raises(TypeError):
- record.value.set(2, 4) # type: ignore
- def test_pmap_field_checked_map_key_multiple_types():
- """
- ``pmap_field`` results in a map that enforces its key types.
- """
- class Record(PRecord):
- value = pmap_field((int, str), type(None))
- record = Record(value={1: None, "hello": None})
- with pytest.raises(TypeError):
- record.value.set(object(), None)
- def test_pmap_field_checked_map_value_multiple_types():
- """
- ``pmap_field`` results in a map that enforces its value types.
- """
- class Record(PRecord):
- value = pmap_field(int, (str, type(None)))
- record = Record(value={1: None, 3: "hello"})
- with pytest.raises(TypeError):
- record.value.set(2, 4)
- def test_pmap_field_mandatory():
- """
- ``pmap_field`` is a mandatory field.
- """
- class Record(PRecord):
- value = pmap_field(int, int)
- record = Record()
- with pytest.raises(InvariantException):
- record.remove("value")
- def test_pmap_field_default_non_optional():
- """
- By default ``pmap_field`` is non-optional, i.e. does not allow
- ``None``.
- """
- class Record(PRecord):
- value = pmap_field(int, int)
- # Ought to be TypeError, but pyrsistent doesn't quite allow that:
- with pytest.raises(AttributeError):
- Record(value=None)
- def test_pmap_field_explicit_non_optional():
- """
- If ``optional`` argument is ``False`` then ``pmap_field`` is
- non-optional, i.e. does not allow ``None``.
- """
- class Record(PRecord):
- value = pmap_field(int, int, optional=False)
- # Ought to be TypeError, but pyrsistent doesn't quite allow that:
- with pytest.raises(AttributeError):
- Record(value=None)
- def test_pmap_field_optional():
- """
- If ``optional`` argument is true, ``None`` is acceptable alternative
- to a set.
- """
- class Record(PRecord):
- value = pmap_field(int, int, optional=True)
- assert (Record(value={1: 2}).value, Record(value=None).value) == \
- (pmap({1: 2}), None)
- def test_pmap_field_name():
- """
- The created map class name is based on the types of items in the map.
- """
- class Record(PRecord):
- value = pmap_field(Something, Another)
- value2 = pmap_field(int, float)
- assert ((Record().value.__class__.__name__,
- Record().value2.__class__.__name__) ==
- ("SomethingToAnotherPMap", "IntToFloatPMap"))
- def test_pmap_field_name_multiple_types():
- """
- The created map class name is based on the types of items in the map,
- including when there are multiple supported types.
- """
- class Record(PRecord):
- value = pmap_field((Something, Another), int)
- value2 = pmap_field(str, (int, float))
- assert ((Record().value.__class__.__name__,
- Record().value2.__class__.__name__) ==
- ("SomethingAnotherToIntPMap", "StrToIntFloatPMap"))
- def test_pmap_field_name_string_type():
- """
- The created map class name is based on the types of items in the map
- specified by name.
- """
- class Record(PRecord):
- value = pmap_field("record_test.Something", "record_test.Another")
- assert Record().value.__class__.__name__ == "SomethingToAnotherPMap"
- def test_pmap_field_name_multiple_string_types():
- """
- The created map class name is based on the types of items in the map,
- including when there are multiple supported types.
- """
- class Record(PRecord):
- value = pmap_field(("record_test.Something", "record_test.Another"), int)
- value2 = pmap_field(str, ("record_test.Something", "record_test.Another"))
- assert ((Record().value.__class__.__name__,
- Record().value2.__class__.__name__) ==
- ("SomethingAnotherToIntPMap", "StrToSomethingAnotherPMap"))
- def test_pmap_field_invariant():
- """
- The ``invariant`` parameter is passed through to ``field``.
- """
- class Record(PRecord):
- value = pmap_field(
- int, int,
- invariant=(
- lambda pmap: (len(pmap) == 1, "Exactly one item required.")
- )
- )
- with pytest.raises(InvariantException):
- Record(value={})
- with pytest.raises(InvariantException):
- Record(value={1: 2, 3: 4})
- assert Record(value={1: 2}).value == {1: 2}
- def test_pmap_field_create_from_nested_serialized_data():
- class Foo(PRecord):
- foo = field(type=str)
- class Bar(PRecord):
- bar = pmap_field(str, Foo)
- data = Bar(bar=m(foo_key=Foo(foo="foo")))
- Bar.create(data.serialize()) == data
- def test_supports_weakref():
- import weakref
- weakref.ref(ARecord(x=1, y=2))
- def test_supports_lazy_initial_value_for_field():
- class MyRecord(PRecord):
- a = field(int, initial=lambda: 2)
- assert MyRecord() == MyRecord(a=2)
- def test_pickle_with_one_way_factory():
- """
- A field factory isn't called when restoring from pickle.
- """
- thing = UniqueThing(id='25544626-86da-4bce-b6b6-9186c0804d64')
- assert thing == pickle.loads(pickle.dumps(thing))
|