|
1 # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 |
|
2 # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt |
|
3 |
|
4 """Determine facts about the environment.""" |
|
5 |
|
6 import os |
|
7 import platform |
|
8 import sys |
|
9 |
|
10 # Operating systems. |
|
11 WINDOWS = sys.platform == "win32" |
|
12 LINUX = sys.platform.startswith("linux") |
|
13 OSX = sys.platform == "darwin" |
|
14 |
|
15 # Python implementations. |
|
16 CPYTHON = (platform.python_implementation() == "CPython") |
|
17 PYPY = (platform.python_implementation() == "PyPy") |
|
18 JYTHON = (platform.python_implementation() == "Jython") |
|
19 IRONPYTHON = (platform.python_implementation() == "IronPython") |
|
20 |
|
21 # Python versions. We amend version_info with one more value, a zero if an |
|
22 # official version, or 1 if built from source beyond an official version. |
|
23 PYVERSION = sys.version_info + (int(platform.python_version()[-1] == "+"),) |
|
24 |
|
25 if PYPY: |
|
26 PYPYVERSION = sys.pypy_version_info |
|
27 |
|
28 # Python behavior. |
|
29 class PYBEHAVIOR: |
|
30 """Flags indicating this Python's behavior.""" |
|
31 |
|
32 # Does Python conform to PEP626, Precise line numbers for debugging and other tools. |
|
33 # https://www.python.org/dev/peps/pep-0626 |
|
34 pep626 = CPYTHON and (PYVERSION > (3, 10, 0, 'alpha', 4)) |
|
35 |
|
36 # Is "if __debug__" optimized away? |
|
37 if PYPY: |
|
38 optimize_if_debug = True |
|
39 else: |
|
40 optimize_if_debug = not pep626 |
|
41 |
|
42 # Is "if not __debug__" optimized away? The exact details have changed |
|
43 # across versions. |
|
44 if pep626: |
|
45 optimize_if_not_debug = 1 |
|
46 elif PYPY: |
|
47 if PYVERSION >= (3, 9): |
|
48 optimize_if_not_debug = 2 |
|
49 elif PYVERSION[:2] == (3, 8): |
|
50 optimize_if_not_debug = 3 |
|
51 else: |
|
52 optimize_if_not_debug = 1 |
|
53 else: |
|
54 if PYVERSION >= (3, 8, 0, 'beta', 1): |
|
55 optimize_if_not_debug = 2 |
|
56 else: |
|
57 optimize_if_not_debug = 1 |
|
58 |
|
59 # Can co_lnotab have negative deltas? |
|
60 negative_lnotab = not (PYPY and PYPYVERSION < (7, 2)) |
|
61 |
|
62 # 3.7 changed how functions with only docstrings are numbered. |
|
63 docstring_only_function = (not PYPY) and ((3, 7, 0, 'beta', 5) <= PYVERSION <= (3, 10)) |
|
64 |
|
65 # When a break/continue/return statement in a try block jumps to a finally |
|
66 # block, does the finally block do the break/continue/return (pre-3.8), or |
|
67 # does the finally jump back to the break/continue/return (3.8) to do the |
|
68 # work? |
|
69 finally_jumps_back = ((3, 8) <= PYVERSION < (3, 10)) |
|
70 |
|
71 # When a function is decorated, does the trace function get called for the |
|
72 # @-line and also the def-line (new behavior in 3.8)? Or just the @-line |
|
73 # (old behavior)? |
|
74 trace_decorated_def = (CPYTHON and PYVERSION >= (3, 8)) or (PYPY and PYVERSION >= (3, 9)) |
|
75 |
|
76 # Functions are no longer claimed to start at their earliest decorator even though |
|
77 # the decorators are traced? |
|
78 def_ast_no_decorator = (PYPY and PYVERSION >= (3, 9)) |
|
79 |
|
80 # CPython 3.11 now jumps to the decorator line again while executing |
|
81 # the decorator. |
|
82 trace_decorator_line_again = (CPYTHON and PYVERSION > (3, 11, 0, 'alpha', 3, 0)) |
|
83 |
|
84 # Are while-true loops optimized into absolute jumps with no loop setup? |
|
85 nix_while_true = (PYVERSION >= (3, 8)) |
|
86 |
|
87 # CPython 3.9a1 made sys.argv[0] and other reported files absolute paths. |
|
88 report_absolute_files = (CPYTHON and PYVERSION >= (3, 9)) |
|
89 |
|
90 # Lines after break/continue/return/raise are no longer compiled into the |
|
91 # bytecode. They used to be marked as missing, now they aren't executable. |
|
92 omit_after_jump = pep626 |
|
93 |
|
94 # PyPy has always omitted statements after return. |
|
95 omit_after_return = omit_after_jump or PYPY |
|
96 |
|
97 # Modules used to have firstlineno equal to the line number of the first |
|
98 # real line of code. Now they always start at 1. |
|
99 module_firstline_1 = pep626 |
|
100 |
|
101 # Are "if 0:" lines (and similar) kept in the compiled code? |
|
102 keep_constant_test = pep626 |
|
103 |
|
104 # When leaving a with-block, do we visit the with-line again for the exit? |
|
105 exit_through_with = (PYVERSION >= (3, 10, 0, 'beta')) |
|
106 |
|
107 # Match-case construct. |
|
108 match_case = (PYVERSION >= (3, 10)) |
|
109 |
|
110 # Some words are keywords in some places, identifiers in other places. |
|
111 soft_keywords = (PYVERSION >= (3, 10)) |
|
112 |
|
113 |
|
114 # Coverage.py specifics. |
|
115 |
|
116 # Are we using the C-implemented trace function? |
|
117 C_TRACER = os.getenv('COVERAGE_TEST_TRACER', 'c') == 'c' |
|
118 |
|
119 # Are we coverage-measuring ourselves? |
|
120 METACOV = os.getenv('COVERAGE_COVERAGE', '') != '' |
|
121 |
|
122 # Are we running our test suite? |
|
123 # Even when running tests, you can use COVERAGE_TESTING=0 to disable the |
|
124 # test-specific behavior like contracts. |
|
125 TESTING = os.getenv('COVERAGE_TESTING', '') == 'True' |
|
126 |
|
127 # Environment COVERAGE_NO_CONTRACTS=1 can turn off contracts while debugging |
|
128 # tests to remove noise from stack traces. |
|
129 # $set_env.py: COVERAGE_NO_CONTRACTS - Disable PyContracts to simplify stack traces. |
|
130 USE_CONTRACTS = ( |
|
131 TESTING |
|
132 and not bool(int(os.environ.get("COVERAGE_NO_CONTRACTS", 0))) |
|
133 and (PYVERSION < (3, 11)) |
|
134 ) |
|
135 |
|
136 def debug_info(): |
|
137 """Return a list of (name, value) pairs for printing debug information.""" |
|
138 info = [ |
|
139 (name, value) for name, value in globals().items() |
|
140 if not name.startswith("_") and |
|
141 name not in {"PYBEHAVIOR", "debug_info"} and |
|
142 not isinstance(value, type(os)) |
|
143 ] |
|
144 info += [ |
|
145 (name, value) for name, value in PYBEHAVIOR.__dict__.items() |
|
146 if not name.startswith("_") |
|
147 ] |
|
148 return sorted(info) |