aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/pyrsistent/py3/tests/class_test.py
diff options
context:
space:
mode:
authorshmel1k <shmel1k@ydb.tech>2023-11-26 18:16:14 +0300
committershmel1k <shmel1k@ydb.tech>2023-11-26 18:43:30 +0300
commitb8cf9e88f4c5c64d9406af533d8948deb050d695 (patch)
tree218eb61fb3c3b96ec08b4d8cdfef383104a87d63 /contrib/python/pyrsistent/py3/tests/class_test.py
parent523f645a83a0ec97a0332dbc3863bb354c92a328 (diff)
downloadydb-b8cf9e88f4c5c64d9406af533d8948deb050d695.tar.gz
add kikimr_configure
Diffstat (limited to 'contrib/python/pyrsistent/py3/tests/class_test.py')
-rw-r--r--contrib/python/pyrsistent/py3/tests/class_test.py474
1 files changed, 474 insertions, 0 deletions
diff --git a/contrib/python/pyrsistent/py3/tests/class_test.py b/contrib/python/pyrsistent/py3/tests/class_test.py
new file mode 100644
index 0000000000..5e953965d5
--- /dev/null
+++ b/contrib/python/pyrsistent/py3/tests/class_test.py
@@ -0,0 +1,474 @@
+from collections.abc import Hashable
+import math
+import pickle
+import pytest
+import uuid
+from pyrsistent import (
+ field, InvariantException, PClass, optional, CheckedPVector,
+ pmap_field, pset_field, pvector_field)
+
+
+class Point(PClass):
+ x = field(type=int, mandatory=True, invariant=lambda x: (x >= 0, 'X negative'))
+ y = field(type=int, serializer=lambda formatter, y: formatter(y))
+ 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)
+ vec = pvector_field(str)
+
+
+class UniqueThing(PClass):
+ id = field(type=uuid.UUID, factory=uuid.UUID)
+ x = field(type=int)
+
+
+def test_create_ignore_extra():
+ p = Point.create({'x': 5, 'y': 10, 'z': 15, 'a': 0}, ignore_extra=True)
+ assert p.x == 5
+ assert p.y == 10
+ assert p.z == 15
+ assert isinstance(p, Point)
+
+
+def test_create_ignore_extra_false():
+ with pytest.raises(AttributeError):
+ _ = Point.create({'x': 5, 'y': 10, 'z': 15, 'a': 0})
+
+
+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)
+
+ # Original remains
+ assert p.x == 1
+ assert p.y == 2
+
+ # Evolved object updated
+ assert p2.x == 3
+ assert p2.y == 2
+
+ p3 = p2.set('x', 4)
+ assert p3.x == 4
+ assert p3.y == 2
+
+
+def test_direct_assignment_not_possible():
+ p = Point(x=1, y=2)
+
+ with pytest.raises(AttributeError):
+ p.x = 1
+
+ with pytest.raises(AttributeError):
+ setattr(p, 'x', 1)
+
+
+def test_direct_delete_not_possible():
+ p = Point(x=1, y=2)
+ with pytest.raises(AttributeError):
+ del p.x
+
+ with pytest.raises(AttributeError):
+ delattr(p, 'x')
+
+
+def test_cannot_construct_with_undeclared_fields():
+ with pytest.raises(AttributeError):
+ Point(x=1, p=5)
+
+
+def test_cannot_construct_with_wrong_type():
+ with pytest.raises(TypeError):
+ Point(x='a')
+
+
+def test_cannot_construct_without_mandatory_fields():
+ try:
+ Point(y=1)
+ assert False
+ except InvariantException as e:
+ assert "[Point.x]" in str(e)
+
+
+def test_field_invariant_must_hold():
+ try:
+ Point(x=-1)
+ assert False
+ except InvariantException as e:
+ assert "X negative" in str(e)
+
+
+def test_initial_value_set_when_not_present_in_arguments():
+ p = Point(x=1, y=2)
+
+ assert p.z == 0
+
+
+class Line(PClass):
+ p1 = field(type=Point)
+ p2 = field(type=Point)
+
+
+def test_can_create_nested_structures_from_dict_and_serialize_back_to_dict():
+ source = dict(p1=dict(x=1, y=2, z=3), p2=dict(x=10, y=20, z=30))
+ l = Line.create(source)
+
+ assert l.p1.x == 1
+ assert l.p1.y == 2
+ assert l.p1.z == 3
+ assert l.p2.x == 10
+ assert l.p2.y == 20
+ assert l.p2.z == 30
+
+ assert l.serialize(format=lambda val: val) == source
+
+
+def test_can_serialize_with_custom_serializer():
+ p = Point(x=1, y=1, z=1)
+
+ assert p.serialize(format=lambda v: v + 17) == {'x': 1, 'y': 18, 'z': 1}
+
+
+def test_implements_proper_equality_based_on_equality_of_fields():
+ p1 = Point(x=1, y=2)
+ p2 = Point(x=3)
+ p3 = Point(x=1, y=2)
+
+ assert p1 == p3
+ assert not p1 != p3
+ assert p1 != p2
+ assert not p1 == p2
+
+
+def test_is_hashable():
+ p1 = Point(x=1, y=2)
+ p2 = Point(x=3, y=2)
+
+ d = {p1: 'A point', p2: 'Another point'}
+
+ p1_like = Point(x=1, y=2)
+ p2_like = Point(x=3, y=2)
+
+ assert isinstance(p1, Hashable)
+ assert d[p1_like] == 'A point'
+ assert d[p2_like] == 'Another point'
+ assert Point(x=10) not in d
+
+
+def test_supports_nested_transformation():
+ l1 = Line(p1=Point(x=2, y=1), p2=Point(x=20, y=10))
+
+ l2 = l1.transform(['p1', 'x'], 3)
+
+ assert l1.p1.x == 2
+
+ assert l2.p1.x == 3
+ assert l2.p1.y == 1
+ assert l2.p2.x == 20
+ assert l2.p2.y == 10
+
+
+def test_repr():
+ class ARecord(PClass):
+ a = field()
+ b = field()
+
+ assert repr(ARecord(a=1, b=2)) in ('ARecord(a=1, b=2)', 'ARecord(b=2, a=1)')
+
+
+def test_global_invariant_check():
+ class UnitCirclePoint(PClass):
+ __invariant__ = lambda cp: (0.99 < math.sqrt(cp.x*cp.x + cp.y*cp.y) < 1.01,
+ "Point not on unit circle")
+ x = field(type=float)
+ y = field(type=float)
+
+ UnitCirclePoint(x=1.0, y=0.0)
+
+ with pytest.raises(InvariantException):
+ UnitCirclePoint(x=1.0, y=1.0)
+
+
+def test_supports_pickling():
+ p1 = Point(x=2, y=1)
+ p2 = pickle.loads(pickle.dumps(p1, -1))
+
+ assert p1 == p2
+ assert isinstance(p2, Point)
+
+
+def test_supports_pickling_with_typed_container_fields():
+ obj = TypedContainerObj(map={'foo': 'bar'}, set=['hello', 'there'], vec=['a', 'b'])
+ obj2 = pickle.loads(pickle.dumps(obj))
+ assert obj == obj2
+
+
+def test_can_remove_optional_member():
+ p1 = Point(x=1, y=2)
+ p2 = p1.remove('y')
+
+ assert p2 == Point(x=1)
+
+
+def test_cannot_remove_mandatory_member():
+ p1 = Point(x=1, y=2)
+
+ with pytest.raises(InvariantException):
+ p1.remove('x')
+
+
+def test_cannot_remove_non_existing_member():
+ p1 = Point(x=1)
+
+ with pytest.raises(AttributeError):
+ p1.remove('y')
+
+
+def test_evolver_without_evolution_returns_original_instance():
+ p1 = Point(x=1)
+ e = p1.evolver()
+
+ assert e.persistent() is p1
+
+
+def test_evolver_with_evolution_to_same_element_returns_original_instance():
+ p1 = Point(x=1)
+ e = p1.evolver()
+ e.set('x', p1.x)
+
+ assert e.persistent() is p1
+
+
+def test_evolver_supports_chained_set_and_remove():
+ p1 = Point(x=1, y=2)
+
+ assert p1.evolver().set('x', 3).remove('y').persistent() == Point(x=3)
+
+
+def test_evolver_supports_dot_notation_for_setting_and_getting_elements():
+ e = Point(x=1, y=2).evolver()
+
+ e.x = 3
+ assert e.x == 3
+ assert e.persistent() == Point(x=3, y=2)
+
+
+class Numbers(CheckedPVector):
+ __type__ = int
+
+
+class LinkedList(PClass):
+ value = field(type='__tests__.class_test.Numbers')
+ next = field(type=optional('__tests__.class_test.LinkedList'))
+
+
+def test_string_as_type_specifier():
+ l = LinkedList(value=[1, 2], next=LinkedList(value=[3, 4], next=None))
+
+ assert isinstance(l.value, Numbers)
+ assert list(l.value) == [1, 2]
+ assert l.next.next is None
+
+
+def test_multiple_invariants_on_field():
+ # If the invariant returns a list of tests the results of running those tests will be
+ # a tuple containing result data of all failing tests.
+
+ class MultiInvariantField(PClass):
+ one = field(type=int, invariant=lambda x: ((False, 'one_one'),
+ (False, 'one_two'),
+ (True, 'one_three')))
+ two = field(invariant=lambda x: (False, 'two_one'))
+
+ try:
+ MultiInvariantField(one=1, two=2)
+ assert False
+ except InvariantException as e:
+ assert set(e.invariant_errors) == set([('one_one', 'one_two'), 'two_one'])
+
+
+def test_multiple_global_invariants():
+ class MultiInvariantGlobal(PClass):
+ __invariant__ = lambda self: ((False, 'x'), (False, 'y'))
+ one = field()
+
+ try:
+ MultiInvariantGlobal(one=1)
+ assert False
+ except InvariantException as e:
+ assert e.invariant_errors == (('x', 'y'),)
+
+
+def test_inherited_global_invariants():
+ class Distant(object):
+ def __invariant__(self):
+ return [(self.distant, "distant")]
+
+ class Nearby(Distant):
+ def __invariant__(self):
+ return [(self.nearby, "nearby")]
+
+ class MultipleInvariantGlobal(Nearby, PClass):
+ distant = field()
+ nearby = field()
+
+ try:
+ MultipleInvariantGlobal(distant=False, nearby=False)
+ assert False
+ except InvariantException as e:
+ assert e.invariant_errors == (("nearby",), ("distant",),)
+
+
+def test_diamond_inherited_global_invariants():
+ counter = []
+ class Base(object):
+ def __invariant__(self):
+ counter.append(None)
+ return [(False, "base")]
+
+ class Left(Base):
+ pass
+
+ class Right(Base):
+ pass
+
+ class SingleInvariantGlobal(Left, Right, PClass):
+ pass
+
+ try:
+ SingleInvariantGlobal()
+ assert False
+ except InvariantException as e:
+ assert e.invariant_errors == (("base",),)
+ assert counter == [None]
+
+def test_supports_weakref():
+ import weakref
+ weakref.ref(Point(x=1, y=2))
+
+
+def test_supports_weakref_with_multi_level_inheritance():
+ import weakref
+
+ class PPoint(Point):
+ a = field()
+
+ weakref.ref(PPoint(x=1, y=2))
+
+
+def test_supports_lazy_initial_value_for_field():
+ class MyClass(PClass):
+ a = field(int, initial=lambda: 2)
+
+ assert MyClass() == MyClass(a=2)
+
+
+def test_type_checks_lazy_initial_value_for_field():
+ class MyClass(PClass):
+ a = field(int, initial=lambda: "a")
+
+ with pytest.raises(TypeError):
+ MyClass()
+
+
+def test_invariant_checks_lazy_initial_value_for_field():
+ class MyClass(PClass):
+ a = field(int, invariant=lambda x: (x < 5, "Too large"), initial=lambda: 10)
+
+ with pytest.raises(InvariantException):
+ MyClass()
+
+
+def test_invariant_checks_static_initial_value():
+ class MyClass(PClass):
+ a = field(int, invariant=lambda x: (x < 5, "Too large"), initial=10)
+
+ with pytest.raises(InvariantException):
+ MyClass()
+
+
+def test_lazy_invariant_message():
+ class MyClass(PClass):
+ a = field(int, invariant=lambda x: (x < 5, lambda: "{x} is too large".format(x=x)))
+
+ try:
+ MyClass(a=5)
+ assert False
+ except InvariantException as e:
+ assert '5 is too large' in e.invariant_errors
+
+
+def test_enum_key_type():
+ import enum
+ class Foo(enum.Enum):
+ Bar = 1
+ Baz = 2
+
+ # This currently fails because the enum is iterable
+ class MyClass1(PClass):
+ f = pmap_field(key_type=Foo, value_type=int)
+
+ MyClass1()
+
+ # This is OK since it's wrapped in a tuple
+ class MyClass2(PClass):
+ f = pmap_field(key_type=(Foo,), value_type=int)
+
+ MyClass2()
+
+
+def test_pickle_with_one_way_factory():
+ thing = UniqueThing(id='25544626-86da-4bce-b6b6-9186c0804d64')
+ assert pickle.loads(pickle.dumps(thing)) == thing
+
+
+def test_evolver_with_one_way_factory():
+ thing = UniqueThing(id='cc65249a-56fe-4995-8719-ea02e124b234')
+ ev = thing.evolver()
+ ev.x = 5 # necessary to prevent persistent() returning the original
+ assert ev.persistent() == UniqueThing(id=str(thing.id), x=5)
+
+
+def test_set_doesnt_trigger_other_factories():
+ thing = UniqueThing(id='b413b280-de76-4e28-a8e3-5470ca83ea2c')
+ thing.set(x=5)
+
+
+def test_set_does_trigger_factories():
+ class SquaredPoint(PClass):
+ x = field(factory=lambda x: x ** 2)
+ y = field()
+
+ sp = SquaredPoint(x=3, y=10)
+ assert (sp.x, sp.y) == (9, 10)
+
+ sp2 = sp.set(x=4)
+ assert (sp2.x, sp2.y) == (16, 10)
+
+
+def test_value_can_be_overridden_in_subclass_new():
+ class X(PClass):
+ y = pvector_field(int)
+
+ def __new__(cls, **kwargs):
+ items = kwargs.get('y', None)
+ if items is None:
+ kwargs['y'] = ()
+ return super(X, cls).__new__(cls, **kwargs)
+
+ a = X(y=[])
+ b = a.set(y=None)
+ assert a == b