Coverage for tests/test_func.py: 80%

107 statements  

« prev     ^ index     » next       coverage.py v7.6.7, created at 2024-11-22 15:39 -0800

1from inspect import signature 

2 

3import pytest 

4 

5import appl 

6from appl import as_func, need_ctx, partial, ppl, records 

7 

8GLOBAL_V = 123 

9 

10 

11def test_docstring(): 

12 @ppl 

13 def func(): 

14 "This is a docstring" 

15 

16 assert func.__doc__ == "This is a docstring" 

17 

18 

19def test_signature(): 

20 @ppl 

21 def add(x: int, y: int) -> int: 

22 return x + y 

23 

24 def add2(x: int, y: int, *, config=None) -> int: 

25 # config (langsmith_extra) is added by langsmith @traceable 

26 return x + y 

27 

28 new_sig = signature(add) 

29 assert new_sig == signature(add.__wrapped__) or new_sig == signature(add2) 

30 

31 

32def test_functionality(): 

33 @ppl 

34 def add(x: int, y: int) -> int: 

35 return x + y 

36 

37 assert add(1, 2) == 3 

38 

39 

40def test_decorator(): 

41 def extra(func): 

42 @need_ctx 

43 def inner(*args, **kwargs): 

44 return func(*args, **kwargs) + 1 

45 

46 return inner 

47 

48 @extra 

49 @ppl 

50 def add(x: int, y: int) -> int: 

51 return x + y 

52 

53 assert add(1, 2) == 4 

54 

55 

56def test_classmethod(): 

57 class A: 

58 @classmethod 

59 @ppl(ctx="same") 

60 def addon(cls): 

61 "addon" 

62 

63 @classmethod 

64 @ppl 

65 def func(cls): 

66 "start" 

67 cls.addon() 

68 return records() 

69 

70 assert str(A.func()) == "start\naddon" 

71 

72 

73def test_super_in_class(): 

74 class A: 

75 def func(self): 

76 return 1 

77 

78 class B(A): 

79 @ppl 

80 def func(self): 

81 return super(B, self).func() 

82 

83 # NOTE: super() is not supported in ppl decorator 

84 # TODO: fix by filling the class name and self in the function during compiling. 

85 assert B().func() == 1 

86 

87 

88def test_nested_ppl_error(): 

89 with pytest.raises(SyntaxError) as excinfo: 

90 

91 @ppl 

92 def func(): 

93 "Hello" 

94 

95 @ppl # nested ppl decorator is not supported yet. 

96 def func2(): 

97 "World" 

98 

99 func2() 

100 return records() 

101 

102 assert "Nested ppl decorator is not" in str(excinfo.value) 

103 

104 

105def test_function_inside_ppl(): 

106 @ppl 

107 def f1(): 

108 "Hello" 

109 

110 def f2(): 

111 "World" 

112 

113 f2() 

114 return records() 

115 

116 assert str(f1()) == "Hello\nWorld" 

117 

118 @ppl 

119 def f3(): 

120 "Hello" 

121 

122 def f4(): 

123 "World" 

124 

125 return records() 

126 

127 assert str(f3()) == "Hello" 

128 

129 

130def test_closure(): 

131 a = 1 

132 

133 @ppl 

134 def func(): 

135 return a 

136 

137 assert func() == a 

138 a = 2 

139 assert func() == a 

140 f = as_func(func) 

141 assert f() == a 

142 

143 b = 1 

144 

145 def f2(): 

146 @ppl 

147 def f3(): 

148 return b 

149 

150 return f3() 

151 

152 assert f2() == b 

153 

154 

155def test_wrapper(): 

156 a = 2 

157 

158 def wrapper(): 

159 a = 1 

160 

161 @ppl 

162 def func(b): 

163 f"{a}+{b}={a+b}" 

164 return records() 

165 

166 return as_func(func) # use as_func to inject the locals of wrapper (a=1) 

167 

168 # if not use as_func, the caller's locals will be used, which is from test_wrapper's locals (a=2) 

169 func = wrapper() 

170 assert str(func(2)) == "1+2=3" 

171 

172 

173def test_global(): 

174 @ppl 

175 def func(): 

176 return GLOBAL_V 

177 

178 assert func() == GLOBAL_V