Coverage for tests / test_context.py: 100.000%

174 statements  

« prev     ^ index     » next       coverage.py v7.12.1a0.dev1, created at 2025-11-30 17:57 +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 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

7 

8import inspect 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

9import os.path 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

10 

11from typing import Any 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

12from unittest import mock 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

13 

14import pytest 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

15 

16import coverage 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

17from coverage.context import qualname_from_frame 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

18from coverage.data import CoverageData, sorted_lines 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

19from coverage.types import TArc, TCovKwargs, TLineNo 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

20 

21from tests import testenv 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

22from tests.coveragetest import CoverageTest 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

23from tests.helpers import assert_count_equal 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

24 

25 

26class StaticContextTest(CoverageTest): 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

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

28 

29 def test_no_context(self) -> None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

30 self.make_file("main.py", "a = 1") 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

31 cov = coverage.Coverage() 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

32 self.start_import_stop(cov, "main") 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

33 data = cov.get_data() 1abcdYefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX

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

35 

36 def test_static_context(self) -> None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

37 self.make_file("main.py", "a = 1") 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

38 cov = coverage.Coverage(context="gooey") 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

39 self.start_import_stop(cov, "main") 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

40 data = cov.get_data() 1abcdefghiZjklmnopqrstuvwxyzABCDEFGHIJ0KLMNO4PQRSTUVWX

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

42 

43 SOURCE = """\ 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

44 a = 1 

45 if a > 2: 

46 a = 3 

47 assert a == 1 

48 """ 

49 

50 LINES = [1, 2, 4] 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

51 

52 def run_red_blue(self, **options: TCovKwargs) -> tuple[CoverageData, CoverageData]: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

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

54 self.make_file("red.py", self.SOURCE) 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

55 red_cov = coverage.Coverage(context="red", data_suffix="r", source=["."], **options) 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

56 self.start_import_stop(red_cov, "red") 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

57 red_cov.save() 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX

58 red_data = red_cov.get_data() 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX

59 

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

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

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

63 blue_cov.save() 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX

64 blue_data = blue_cov.get_data() 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX

65 

66 return red_data, blue_data 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX

67 

68 def test_combining_line_contexts(self) -> None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

69 red_data, blue_data = self.run_red_blue() 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

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

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

72 for data in datas: 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNOPQRST3UVWX

73 combined.update(data) 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNOPQRST3UVWX

74 

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

76 

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

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

79 

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

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

82 

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

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

85 combined.set_query_context(context) 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

86 assert combined.lines(filename) == lines 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

87 

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

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

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

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

92 

93 def test_combining_arc_contexts(self) -> None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

94 red_data, blue_data = self.run_red_blue(branch=True) 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

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( 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX

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

100 ) 

101 assert arc_data is not None 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX

102 

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

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

105 for data in datas: 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX

106 combined.update(data) 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX

107 

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

109 

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

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

112 

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

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

115 

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

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

118 combined.set_query_context(context) 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

119 assert combined.lines(filename) == lines 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

120 

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

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

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

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

125 

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

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

128 combined.set_query_context(context) 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

129 assert combined.arcs(filename) == lines 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

130 

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

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

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

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

135 

136 

137@pytest.mark.skipif(not testenv.DYN_CONTEXTS, reason="No dynamic contexts with this core") 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

138class DynamicContextTest(CoverageTest): 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

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

140 

141 SOURCE = """\ 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

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] 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

165 TEST_ONE_LINES = [5, 6, 2] 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

166 TEST_TWO_LINES = [9, 10, 11, 13, 14, 15, 2] 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

167 

168 def test_dynamic_alone(self) -> None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

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

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

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

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

173 data = cov.get_data() 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX

174 

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

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

177 assert_count_equal( 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX

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: 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX

183 data.set_query_context(context) 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX

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

185 

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

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

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

189 

190 def test_static_and_dynamic(self) -> None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

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

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

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

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

195 data = cov.get_data() 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX

196 

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

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

199 assert_count_equal( 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX

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: 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX

205 data.set_query_context(context) 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX

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

207 

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

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

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

211 

212 

213def get_qualname() -> str | None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

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

215 stack = inspect.stack()[1:] 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

216 if any(sinfo[0].f_code.co_name == "get_qualname" for sinfo in stack): 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

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] 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

220 caller_frame = stack[0][0] 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

221 return qualname_from_frame(caller_frame) 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

222 

223 

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

225 

226 

227class Parent: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

228 def meth(self) -> str | None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

229 return get_qualname() 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

230 

231 @property 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

232 def a_property(self) -> str | None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

233 return get_qualname() 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

234 

235 

236class Child(Parent): 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

237 pass 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

238 

239 

240class SomethingElse: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

241 pass 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

242 

243 

244class MultiChild(SomethingElse, Child): 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

245 pass 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

246 

247 

248def no_arguments() -> str | None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

249 return get_qualname() 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

250 

251 

252def plain_old_function(a: Any, b: Any) -> str | None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

253 return get_qualname() 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

254 

255 

256def fake_out(self: Any) -> str | None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

257 return get_qualname() 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

258 

259 

260def patch_meth(self: Any) -> str | None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

261 return get_qualname() 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

262 

263 

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

265 

266 

267class QualnameTest(CoverageTest): 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

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 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

274 

275 def test_method(self) -> None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

276 assert Parent().meth() == "tests.test_context.Parent.meth" 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

277 

278 def test_inherited_method(self) -> None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

279 assert Child().meth() == "tests.test_context.Parent.meth" 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

280 

281 def test_mi_inherited_method(self) -> None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

282 assert MultiChild().meth() == "tests.test_context.Parent.meth" 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

283 

284 def test_no_arguments(self) -> None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

285 assert no_arguments() == "tests.test_context.no_arguments" 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

286 

287 def test_plain_old_function(self) -> None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

288 assert plain_old_function(0, 1) == "tests.test_context.plain_old_function" 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

289 

290 def test_fake_out(self) -> None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

291 assert fake_out(0) == "tests.test_context.fake_out" 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

292 

293 def test_property(self) -> None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

294 assert Parent().a_property == "tests.test_context.Parent.a_property" 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

295 

296 def test_changeling(self) -> None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

297 c = Child() 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

298 c.meth = patch_meth # type: ignore[assignment] 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

299 assert c.meth(c) == "tests.test_context.patch_meth" # type: ignore[call-arg] 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

300 

301 def test_bug_829(self) -> None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

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

303 class test_something: # pylint: disable=unused-variable 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

304 assert get_qualname() is None 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

305 

306 def test_bug_1210(self) -> None: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

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"]) 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

310 frame = mock.Mock(f_code=co, f_locals={}) 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX

311 assert qualname_from_frame(frame) == "unittest.mock.a_co_name" 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX