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
« 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
4"""Tests for context support."""
6from __future__ import annotations 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX
8import inspect 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX
9import os.path 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX
11from typing import Any 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX
12from unittest import mock 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX
14import pytest 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX
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
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
26class StaticContextTest(CoverageTest): 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX
27 """Tests of the static context."""
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
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
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 """
50 LINES = [1, 2, 4] 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX
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
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
66 return red_data, blue_data 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX
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
75 assert combined.measured_contexts() == {"red", "blue"} 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNOPQRST3UVWX
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
80 fred = full_names["red.py"] 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNOPQRST3UVWX
81 fblue = full_names["blue.py"] 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNOPQRST3UVWX
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
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
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
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
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
108 assert combined.measured_contexts() == {"red", "blue"} 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX
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
113 fred = full_names["red.py"] 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX
114 fblue = full_names["blue.py"] 1abcdYefghiZjklmnopqrst1uvwxyzABCDE2FGHIJ0KLMNO4PQRST3UVWX
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
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
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
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
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."""
141 SOURCE = """\ 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX
142 def helper(lineno):
143 x = 2
145 def test_one():
146 a = 5
147 helper(6)
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)
158 test_one()
159 x = 18
160 helper(19)
161 test_two()
162 """
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
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
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 )
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
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
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
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 )
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
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
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
224# pylint: disable=missing-class-docstring, missing-function-docstring, unused-argument
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
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
236class Child(Parent): 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX
237 pass 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX
240class SomethingElse: 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX
241 pass 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX
244class MultiChild(SomethingElse, Child): 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX
245 pass 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX
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
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
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
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
264# pylint: enable=missing-class-docstring, missing-function-docstring, unused-argument
267class QualnameTest(CoverageTest): 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX
268 """Tests of qualname_from_frame."""
270 # Pylint gets confused about meth() below.
271 # pylint: disable=no-value-for-parameter
273 run_in_temp_dir = False 1abcdYefghiZjklmnopqrst1uvwxyzABC5DE62F7GH8IJ90K!LM#NO$4P%QR'ST(3U)VWX
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
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
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
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
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
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
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
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
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
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