Coverage for tests / test_context.py: 100.000%

174 statements  

« prev     ^ index     » next       coverage.py v7.12.1a0.dev1, created at 2025-11-29 20:34 +0000

1# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 

2# For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt 

3 

4"""Tests for context support.""" 

5 

6from __future__ import annotations 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

7 

8import inspect 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

9import os.path 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

10 

11from typing import Any 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

12from unittest import mock 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

13 

14import pytest 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

15 

16import coverage 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

17from coverage.context import qualname_from_frame 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

18from coverage.data import CoverageData, sorted_lines 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

19from coverage.types import TArc, TCovKwargs, TLineNo 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

20 

21from tests import testenv 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

22from tests.coveragetest import CoverageTest 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

23from tests.helpers import assert_count_equal 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

24 

25 

26class StaticContextTest(CoverageTest): 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

27 """Tests of the static context.""" 

28 

29 def test_no_context(self) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

30 self.make_file("main.py", "a = 1") 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

31 cov = coverage.Coverage() 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

32 self.start_import_stop(cov, "main") 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

33 data = cov.get_data() 1abcdXefghijklmnopqrs0tuvwxyzABCDEFGHIJKLMNOPQRSTUVW

34 assert_count_equal(data.measured_contexts(), [""]) 1abcdXefghijklmnopqrs0tuvwxyzABCDEFGHIJKLMNOPQRSTUVW

35 

36 def test_static_context(self) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

37 self.make_file("main.py", "a = 1") 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

38 cov = coverage.Coverage(context="gooey") 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

39 self.start_import_stop(cov, "main") 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

40 data = cov.get_data() 1abcdefghiYjklmnZopqrstuvwxyzABCD1EFGHI3JKLMNOPQRS4TUVW

41 assert_count_equal(data.measured_contexts(), ["gooey"]) 1abcdefghiYjklmnZopqrstuvwxyzABCD1EFGHI3JKLMNOPQRS4TUVW

42 

43 SOURCE = """\ 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

44 a = 1 

45 if a > 2: 

46 a = 3 

47 assert a == 1 

48 """ 

49 

50 LINES = [1, 2, 4] 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

51 

52 def run_red_blue(self, **options: TCovKwargs) -> tuple[CoverageData, CoverageData]: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

53 """Run red.py and blue.py, and return their CoverageData objects.""" 

54 self.make_file("red.py", self.SOURCE) 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

55 red_cov = coverage.Coverage(context="red", data_suffix="r", source=["."], **options) 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

56 self.start_import_stop(red_cov, "red") 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

57 red_cov.save() 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

58 red_data = red_cov.get_data() 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

59 

60 self.make_file("blue.py", self.SOURCE) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

61 blue_cov = coverage.Coverage(context="blue", data_suffix="b", source=["."], **options) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

62 self.start_import_stop(blue_cov, "blue") 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

63 blue_cov.save() 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

64 blue_data = blue_cov.get_data() 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

65 

66 return red_data, blue_data 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

67 

68 def test_combining_line_contexts(self) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

69 red_data, blue_data = self.run_red_blue() 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

70 for datas in [[red_data, blue_data], [blue_data, red_data]]: 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHIJKLMN2OPQRSTUVW

71 combined = CoverageData(suffix="combined") 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHIJKLMN2OPQRSTUVW

72 for data in datas: 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHIJKLMN2OPQRSTUVW

73 combined.update(data) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHIJKLMN2OPQRSTUVW

74 

75 assert combined.measured_contexts() == {"red", "blue"} 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHIJKLMN2OPQRSTUVW

76 

77 full_names = {os.path.basename(f): f for f in combined.measured_files()} 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHIJKLMN2OPQRSTUVW

78 assert_count_equal(full_names, ["red.py", "blue.py"]) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHIJKLMN2OPQRSTUVW

79 

80 fred = full_names["red.py"] 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHIJKLMN2OPQRSTUVW

81 fblue = full_names["blue.py"] 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHIJKLMN2OPQRSTUVW

82 

83 def assert_combined_lines(filename: str, context: str, lines: list[TLineNo]) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHIJKLMN2OPQRSTUVW

84 # pylint: disable=cell-var-from-loop 

85 combined.set_query_context(context) 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

86 assert combined.lines(filename) == lines 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

87 

88 assert_combined_lines(fred, "red", self.LINES) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHIJKLMN2OPQRSTUVW

89 assert_combined_lines(fred, "blue", []) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHIJKLMN2OPQRSTUVW

90 assert_combined_lines(fblue, "red", []) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHIJKLMN2OPQRSTUVW

91 assert_combined_lines(fblue, "blue", self.LINES) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHIJKLMN2OPQRSTUVW

92 

93 def test_combining_arc_contexts(self) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

94 red_data, blue_data = self.run_red_blue(branch=True) 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

95 

96 # The exact arc data changes depending on the core and the version. 

97 # Extract the red arc data for comparisons below. 

98 arc_data = red_data.arcs( 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

99 next(fname for fname in red_data.measured_files() if "red.py" in fname) 

100 ) 

101 assert arc_data is not None 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

102 

103 for datas in [[red_data, blue_data], [blue_data, red_data]]: 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

104 combined = CoverageData(suffix="combined") 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

105 for data in datas: 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

106 combined.update(data) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

107 

108 assert combined.measured_contexts() == {"red", "blue"} 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

109 

110 full_names = {os.path.basename(f): f for f in combined.measured_files()} 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

111 assert_count_equal(full_names, ["red.py", "blue.py"]) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

112 

113 fred = full_names["red.py"] 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

114 fblue = full_names["blue.py"] 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

115 

116 def assert_combined_lines(filename: str, context: str, lines: list[TLineNo]) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

117 # pylint: disable=cell-var-from-loop 

118 combined.set_query_context(context) 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

119 assert combined.lines(filename) == lines 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

120 

121 assert_combined_lines(fred, "red", self.LINES) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

122 assert_combined_lines(fred, "blue", []) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

123 assert_combined_lines(fblue, "red", []) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

124 assert_combined_lines(fblue, "blue", self.LINES) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

125 

126 def assert_combined_arcs(filename: str, context: str, lines: list[TArc]) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

127 # pylint: disable=cell-var-from-loop 

128 combined.set_query_context(context) 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

129 assert combined.arcs(filename) == lines 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

130 

131 assert_combined_arcs(fred, "red", arc_data) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

132 assert_combined_arcs(fred, "blue", []) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

133 assert_combined_arcs(fblue, "red", []) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

134 assert_combined_arcs(fblue, "blue", arc_data) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

135 

136 

137@pytest.mark.skipif(not testenv.DYN_CONTEXTS, reason="No dynamic contexts with this core") 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

138class DynamicContextTest(CoverageTest): 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

139 """Tests of dynamically changing contexts.""" 

140 

141 SOURCE = """\ 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

142 def helper(lineno): 

143 x = 2 

144 

145 def test_one(): 

146 a = 5 

147 helper(6) 

148 

149 def test_two(): 

150 a = 9 

151 b = 10 

152 if a > 11: 

153 b = 12 

154 assert a == (13-4) 

155 assert b == (14-4) 

156 helper(15) 

157 

158 test_one() 

159 x = 18 

160 helper(19) 

161 test_two() 

162 """ 

163 

164 OUTER_LINES = [1, 4, 8, 17, 18, 19, 2, 20] 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

165 TEST_ONE_LINES = [5, 6, 2] 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

166 TEST_TWO_LINES = [9, 10, 11, 13, 14, 15, 2] 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

167 

168 def test_dynamic_alone(self) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

169 self.make_file("two_tests.py", self.SOURCE) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

170 cov = coverage.Coverage(source=["."]) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

171 cov.set_option("run:dynamic_context", "test_function") 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

172 self.start_import_stop(cov, "two_tests") 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

173 data = cov.get_data() 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

174 

175 full_names = {os.path.basename(f): f for f in data.measured_files()} 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

176 fname = full_names["two_tests.py"] 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

177 assert_count_equal( 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

178 data.measured_contexts(), 

179 ["", "two_tests.test_one", "two_tests.test_two"], 

180 ) 

181 

182 def assert_context_lines(context: str, lines: list[TLineNo]) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

183 data.set_query_context(context) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

184 assert_count_equal(lines, sorted_lines(data, fname)) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

185 

186 assert_context_lines("", self.OUTER_LINES) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

187 assert_context_lines("two_tests.test_one", self.TEST_ONE_LINES) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

188 assert_context_lines("two_tests.test_two", self.TEST_TWO_LINES) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

189 

190 def test_static_and_dynamic(self) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

191 self.make_file("two_tests.py", self.SOURCE) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

192 cov = coverage.Coverage(context="stat", source=["."]) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

193 cov.set_option("run:dynamic_context", "test_function") 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

194 self.start_import_stop(cov, "two_tests") 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

195 data = cov.get_data() 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

196 

197 full_names = {os.path.basename(f): f for f in data.measured_files()} 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

198 fname = full_names["two_tests.py"] 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

199 assert_count_equal( 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

200 data.measured_contexts(), 

201 ["stat", "stat|two_tests.test_one", "stat|two_tests.test_two"], 

202 ) 

203 

204 def assert_context_lines(context: str, lines: list[TLineNo]) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

205 data.set_query_context(context) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

206 assert_count_equal(lines, sorted_lines(data, fname)) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

207 

208 assert_context_lines("stat", self.OUTER_LINES) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

209 assert_context_lines("stat|two_tests.test_one", self.TEST_ONE_LINES) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

210 assert_context_lines("stat|two_tests.test_two", self.TEST_TWO_LINES) 1abcdXefghiYjklmnZopqrs0tuvwxyzABCD1EFGHI3JKLMN2OPQRS4TUVW

211 

212 

213def get_qualname() -> str | None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

214 """Helper to return qualname_from_frame for the caller.""" 

215 stack = inspect.stack()[1:] 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

216 if any(sinfo[0].f_code.co_name == "get_qualname" for sinfo in stack): 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

217 # We're calling ourselves recursively, maybe because we're testing 

218 # properties. Return an int to try to get back on track. 

219 return 17 # type: ignore[return-value] 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

220 caller_frame = stack[0][0] 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

221 return qualname_from_frame(caller_frame) 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

222 

223 

224# pylint: disable=missing-class-docstring, missing-function-docstring, unused-argument 

225 

226 

227class Parent: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

228 def meth(self) -> str | None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

229 return get_qualname() 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

230 

231 @property 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

232 def a_property(self) -> str | None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

233 return get_qualname() 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

234 

235 

236class Child(Parent): 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

237 pass 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

238 

239 

240class SomethingElse: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

241 pass 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

242 

243 

244class MultiChild(SomethingElse, Child): 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

245 pass 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

246 

247 

248def no_arguments() -> str | None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

249 return get_qualname() 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

250 

251 

252def plain_old_function(a: Any, b: Any) -> str | None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

253 return get_qualname() 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

254 

255 

256def fake_out(self: Any) -> str | None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

257 return get_qualname() 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

258 

259 

260def patch_meth(self: Any) -> str | None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

261 return get_qualname() 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

262 

263 

264# pylint: enable=missing-class-docstring, missing-function-docstring, unused-argument 

265 

266 

267class QualnameTest(CoverageTest): 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

268 """Tests of qualname_from_frame.""" 

269 

270 # Pylint gets confused about meth() below. 

271 # pylint: disable=no-value-for-parameter 

272 

273 run_in_temp_dir = False 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

274 

275 def test_method(self) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

276 assert Parent().meth() == "tests.test_context.Parent.meth" 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

277 

278 def test_inherited_method(self) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

279 assert Child().meth() == "tests.test_context.Parent.meth" 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

280 

281 def test_mi_inherited_method(self) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

282 assert MultiChild().meth() == "tests.test_context.Parent.meth" 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

283 

284 def test_no_arguments(self) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

285 assert no_arguments() == "tests.test_context.no_arguments" 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

286 

287 def test_plain_old_function(self) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

288 assert plain_old_function(0, 1) == "tests.test_context.plain_old_function" 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

289 

290 def test_fake_out(self) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

291 assert fake_out(0) == "tests.test_context.fake_out" 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

292 

293 def test_property(self) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

294 assert Parent().a_property == "tests.test_context.Parent.a_property" 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

295 

296 def test_changeling(self) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

297 c = Child() 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

298 c.meth = patch_meth # type: ignore[assignment] 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

299 assert c.meth(c) == "tests.test_context.patch_meth" # type: ignore[call-arg] 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

300 

301 def test_bug_829(self) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

302 # A class with a name like a function shouldn't confuse qualname_from_frame. 

303 class test_something: # pylint: disable=unused-variable 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

304 assert get_qualname() is None 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

305 

306 def test_bug_1210(self) -> None: 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

307 # Under pyarmor (an obfuscator), a function can have a "self" argument, 

308 # but then not have a "self" local. 

309 co = mock.Mock(co_name="a_co_name", co_argcount=1, co_varnames=["self"]) 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

310 frame = mock.Mock(f_code=co, f_locals={}) 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW

311 assert qualname_from_frame(frame) == "unittest.mock.a_co_name" 1abcdXefghiYjklmnZopqrs0tuvwxyzAB5CD61E7FG8HI93J!KL#MN$2O%PQ'RS(4T)UVW