Coverage for pyfields/tests/test_so.py: 99%

126 statements  

« 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. 

4 

5import pytest 

6 

7from pyfields import ReadOnlyFieldError 

8from valid8 import ValidationError 

9 

10 

11def test_so0(capsys): 

12 """ Checks answer at https://stackoverflow.com/a/58344434/7262247 """ 

13 

14 from pyfields import field, init_fields 

15 

16 with capsys.disabled(): 

17 class C(object): 

18 x = field(default=None, doc="the optional 'x' property") 

19 y = field(doc="the mandatory 'y' property") 

20 z = field(doc="the mandatory 'z' property") 

21 

22 @init_fields 

23 def __init__(self): 

24 pass 

25 

26 c = C(y=1, z=2) 

27 print(vars(c)) 

28 

29 with capsys.disabled(): 

30 out, err = capsys.readouterr() 

31 print(out) 

32 # assert out == """{'y': 1, 'x': None, 'z': 2}\n""" 

33 assert vars(c) == {'y': 1, 'x': None, 'z': 2} 

34 

35 

36def test_so1(capsys): 

37 """ Checks answer at https://stackoverflow.com/a/58344853/7262247 """ 

38 

39 from pyfields import field, init_fields 

40 

41 class Account(object): 

42 first = field(doc="first name") 

43 last = field(doc="last name") 

44 age = field(doc="the age in years") 

45 id = field(doc="an identifier") 

46 balance = field(doc="current balance in euros") 

47 

48 @init_fields 

49 def __init__(self, msg): 

50 print(msg) 

51 

52 a = Account("hello, world!", first="s", last="marie", age=135, id=0, balance=-200000) 

53 print(vars(a)) 

54 with capsys.disabled(): 

55 out, err = capsys.readouterr() 

56 print(out) 

57 assert out.splitlines()[0] == "hello, world!" 

58 assert vars(a) == {'age': 135, 'balance': -200000, 'last': 'marie', 'id': 0, 'first': 's'} 

59 

60 

61def test_so2(): 

62 """ Checks that answer at https://stackoverflow.com/a/58383062/7262247 is ok """ 

63 

64 from pyfields import field 

65 

66 class Position(object): 

67 x = field(validators=lambda x: x > 0) 

68 y = field(validators={'y should be between 0 and 100': lambda y: y > 0 and y < 100}) 

69 

70 p = Position() 

71 p.x = 1 

72 with pytest.raises(ValidationError) as exc_info: 

73 p.y = 101 

74 qualname = Position.y.qualname 

75 assert str(exc_info.value) == "Error validating [%s=101]. " \ 

76 "InvalidValue: y should be between 0 and 100. " \ 

77 "Function [<lambda>] returned [False] for value 101." % qualname 

78 

79 

80def test_so3(): 

81 """https://stackoverflow.com/a/58391645/7262247""" 

82 

83 from pyfields import field 

84 

85 class Spam(object): 

86 description = field(validators={"description can not be empty": lambda s: len(s) > 0}) 

87 value = field(validators={"value must be greater than zero": lambda x: x > 0}) 87 ↛ exitline 87 didn't run the lambda on line 87

88 

89 s = Spam() 

90 with pytest.raises(ValidationError) as exc_info: 

91 s.description = "" 

92 qualname = Spam.description.qualname 

93 assert str(exc_info.value) == "Error validating [%s='']. " \ 

94 "InvalidValue: description can not be empty. " \ 

95 "Function [<lambda>] returned [False] for value ''." % qualname 

96 

97 

98def test_so4(): 

99 """check https://stackoverflow.com/a/58394381/7262247""" 

100 

101 from pyfields import field, init_fields 

102 from valid8.validation_lib import is_in 

103 

104 ALLOWED_COLORS = ('blue', 'yellow', 'brown') 

105 

106 class Car(object): 

107 """ My class with many fields """ 

108 color = field(type_hint=str, check_type=True, validators=is_in(ALLOWED_COLORS)) 

109 name = field(type_hint=str, check_type=True, validators={'should be non-empty': lambda s: len(s) > 0}) 

110 wheels = field(type_hint=int, check_type=True, validators={'should be positive': lambda x: x > 0}) 

111 

112 @init_fields 

113 def __init__(self, msg="hello world!"): 

114 print(msg) 

115 

116 c = Car(color='blue', name='roadie', wheels=3) 

117 assert vars(c) == {'_wheels': 3, '_name': 'roadie', '_color': 'blue'} 

118 

119 qualname = Car.wheels.qualname 

120 

121 with pytest.raises(TypeError) as exc_info: 

122 c.wheels = 'hello' 

123 assert str(exc_info.value) == "Invalid value type provided for '%s'. " \ 

124 "Value should be of type %r. " \ 

125 "Instead, received a 'str': 'hello'" % (qualname, int) 

126 

127 with pytest.raises(ValidationError) as exc_info: 

128 c.wheels = 0 

129 assert str(exc_info.value) == "Error validating [%s=0]. " \ 

130 "InvalidValue: should be positive. " \ 

131 "Function [<lambda>] returned [False] for value 0." % qualname 

132 

133 

134def test_so5(): 

135 """https://stackoverflow.com/a/58395677/7262247""" 

136 

137 from pyfields import field, copy_value, init_fields 

138 from valid8.validation_lib import is_in 

139 

140 class Well(object): 

141 name = field() # Required 

142 group = field() # Required 

143 operate_list = field(default_factory=copy_value([])) # Optional 

144 monitor_list = field(default_factory=copy_value([])) # Optional 

145 geometry = field(default=None) # Optional 

146 perf = field(default=None) # Optional 

147 

148 valid_types = ('type_A', 'type_B') 

149 

150 class Operate(object): 

151 att = field() # Required 

152 type_ = field(type_hint=str, check_type=True, validators=is_in(valid_types)) # Required 

153 value = field(default_factory=copy_value([])) # Optional 

154 mode = field(default=None) # Optional 

155 action = field(default=None) # Optional 

156 

157 @init_fields 

158 def __init__(self): 

159 pass 

160 

161 o = Operate(att="foo", type_='type_A') 

162 

163 with pytest.raises(TypeError): 

164 o.type_ = 1 # <-- raises TypeError: Invalid value type provided 

165 

166 with pytest.raises(ValidationError): 

167 bad_o = Operate(att="foo", type_='type_WRONG') # <-- raises ValidationError: NotInAllowedValues: x in ('type_A', 'type_B') does not hold for x=type_WRONG 

168 

169 

170def test_so6(): 

171 """checks that answer at https://stackoverflow.com/a/58396678/7262247 works""" 

172 from pyfields import field, init_fields 

173 

174 class Position(object): 

175 x = field(type_hint=int, check_type=True, validators=lambda x: x > 0) 

176 y = field(type_hint=int, check_type=True, validators={'y should be between 0 and 100': lambda y: y > 0 and y < 100}) 

177 

178 @init_fields 

179 def __init__(self, msg="hello world!"): 

180 print(msg) 

181 

182 p = Position(x=1, y=12) 

183 with pytest.raises(TypeError) as exc_info: 

184 p.x = '1' 

185 qualname = Position.x.qualname 

186 assert str(exc_info.value) == "Invalid value type provided for '%s'. " \ 

187 "Value should be of type %r. Instead, received a 'str': '1'" % (qualname, int) 

188 

189 with pytest.raises(ValidationError) as exc_info: 

190 p.y = 101 

191 

192 

193def test_so7(): 

194 """ checks answer at https://stackoverflow.com/a/58432813/7262247 """ 

195 

196 from pyfields import field 

197 

198 class User(object): 

199 username = field(read_only=True, validators={'should contain more than 2 characters': lambda s: len(s) > 2}) 

200 

201 u = User() 

202 u.username = "earthling" 

203 assert vars(u) == {'_username': "earthling"} 

204 with pytest.raises(ReadOnlyFieldError) as exc_info: 

205 u.username = "earthling2" 

206 qualname = User.username.qualname 

207 assert str(exc_info.value) == "Read-only field '%s' has already been initialized on instance %s and cannot be " \ 

208 "modified anymore." % (qualname, u)