Coverage for pyfields/tests/test_autofields.py: 95%
119 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-11-06 16:35 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-11-06 16:35 +0000
1# Authors: Sylvain Marie <sylvain.marie@se.com>
2#
3# Copyright (c) Schneider Electric Industries, 2019. All right reserved.
4import sys
6import pytest
8from pyfields import autofields, field, FieldTypeError, Field, get_fields, autoclass
9from pyfields.core import NativeField
12@pytest.mark.parametrize("with_type_hints,type_check", [(False, False), (True, False), (True, True)])
13def test_autofields_basic(with_type_hints, type_check):
14 """tests that basic functionality of @autofields is ok """
16 if with_type_hints:
17 if sys.version_info < (3, 6): 17 ↛ 18line 17 didn't jump to line 18, because the condition on line 17 was never true
18 pytest.skip("Type annotations are not supported in python < 3.6")
20 from ._test_py36 import _test_autofields
21 Foo = _test_autofields(type_check)
23 # test it
24 assert isinstance(Foo.__dict__['barcls'], NativeField)
25 assert isinstance(Foo.__dict__['barfunc'], Field)
26 assert not isinstance(Foo.__dict__['fct'], Field)
27 assert not isinstance(Foo.__dict__['cls'], Field)
29 f = Foo(foo=1, barbar='yo', barfunc=lambda x: 2, barcls=str)
30 if type_check:
31 with pytest.raises(FieldTypeError):
32 f.foo = 'ha'
33 else:
34 f.foo = 'ha'
36 assert f.bar == 0
37 assert f.fct() == 1
38 assert f.barfunc(1) == 2
39 assert f.barcls == str
41 else:
42 # retrocompatbility mode for python < 3.6
43 # note: we also use this opportunity to test with parenthesis
44 @autofields(check_types=type_check)
45 class Foo(object):
46 CONSTANT = 's'
47 __a__ = 0
49 foo = field()
50 bar = 0 # type: int
51 barcls = float
52 barfunc = lambda x: x 52 ↛ exitline 52 didn't run the lambda on line 52
53 barbar = 0 # type: str
55 class cls:
56 pass
58 def fct(self):
59 return 1
61 # test it
62 assert isinstance(Foo.__dict__['barcls'], Field)
63 assert isinstance(Foo.__dict__['barfunc'], Field)
64 assert not isinstance(Foo.__dict__['fct'], Field)
65 assert not isinstance(Foo.__dict__['cls'], Field)
67 f = Foo(foo=1, barfunc=lambda x: 2, barcls=str)
68 assert f.bar == 0
69 assert f.fct() == 1
70 assert f.barfunc(1) == 2
71 assert f.barcls == str
74def test_autofields_property_descriptors():
75 """Checks that properties and descriptors are correctly ignored by autofields"""
77 @autofields
78 class Foo(object):
79 foo = 1
80 @property
81 def bar(self):
82 return 2
84 class MyDesc():
85 def __get__(self):
86 return 1
88 class MyDesc2():
89 def __get__(self):
90 return 0
91 def __set__(self, instance, value):
92 return
94 m = MyDesc()
95 p = MyDesc2()
97 fields = get_fields(Foo)
98 assert len(fields) == 1
99 assert fields[0].name == 'foo'
102@pytest.mark.skipif(sys.version_info < (3, 6), reason="Annotations not supported in python < 3.6")
103def test_issue_74():
104 """test associated with the non-issue 74"""
105 from ._test_py36 import test_issue_74
106 City = test_issue_74()
107 c = City(name=None)
108 assert c.name is None
109 assert c.buildings == []
112@pytest.mark.skipif(sys.version_info < (3, 6), reason="Annotations not supported in python < 3.6")
113def test_issue_76():
114 """ order issue 76 and 77 are fixed """
115 from ._test_py36 import test_issue_76
116 Foo = test_issue_76()
117 assert [f.name for f in get_fields(Foo)] == ['c', 'b', 'a']
120def test_issue_76_bis():
121 """ another order issue with @autofields """
123 @autofields
124 class Foo(object):
125 msg = field(type_hint=str)
126 age = field(default=12, type_hint=int)
128 assert [f.name for f in get_fields(Foo)] == ['msg', 'age']
131def test_autoclass():
132 """"""
134 @autoclass
135 class Foo(object):
136 msg = field(type_hint=str)
137 age = field(default=12, type_hint=int)
139 f = Foo('hey')
141 # str repr
142 assert repr(f) == "Foo(msg='hey', age=12)"
143 assert str(f) == repr(f)
145 # dict and eq
146 assert f.to_dict() == {'msg': 'hey', 'age': 12}
148 same_dict = {'msg': 'hey', 'age': 12}
149 assert f == same_dict
150 assert f == Foo.from_dict(same_dict)
152 diff_dict = {'age': 13, 'msg': 'hey'}
153 assert f != diff_dict
154 assert f != Foo.from_dict(diff_dict)
156 assert f == Foo.from_dict(f.to_dict())
158 # hash
159 my_set = {f, f}
160 assert my_set == {f}
161 assert Foo('hey') in my_set
162 my_set.remove(Foo('hey'))
163 assert len(my_set) == 0
165 # subclass A
166 class Bar(Foo):
167 pass
169 b = Bar(msg='hey')
170 assert str(b) == "Bar(msg='hey', age=12)"
171 assert b == f
172 assert f == b
174 # hash
175 my_set = {f, b}
176 assert len(my_set) == 1 # yes: since the subclass does not define additional attributes.
177 assert my_set == {f}
179 # subclass B
180 @autoclass
181 class Bar2(Foo):
182 ho = 3
184 b2 = Bar2('hey')
185 assert str(b2) == "Bar2(msg='hey', age=12, ho=3)"
186 assert b2 != f
187 assert f != b2
189 # hash
190 my_set = {b2, b}
191 assert Bar2('hey') in my_set