eric7/DebugClients/Python/coverage/collector.py

branch
eric7
changeset 8929
fcca2fa618bf
parent 8775
0802ae193343
child 9099
0e511e0e94a3
equal deleted inserted replaced
8928:d856023fbeb0 8929:fcca2fa618bf
5 5
6 import os 6 import os
7 import sys 7 import sys
8 8
9 from coverage import env 9 from coverage import env
10 from coverage.config import CoverageConfig
10 from coverage.debug import short_stack 11 from coverage.debug import short_stack
11 from coverage.disposition import FileDisposition 12 from coverage.disposition import FileDisposition
12 from coverage.exceptions import CoverageException 13 from coverage.exceptions import ConfigError
13 from coverage.misc import human_sorted, isolate_module 14 from coverage.misc import human_sorted, isolate_module
14 from coverage.pytracer import PyTracer 15 from coverage.pytracer import PyTracer
15 16
16 os = isolate_module(os) 17 os = isolate_module(os)
17 18
53 # and popped when stopped. Collectors on the stack are paused when not 54 # and popped when stopped. Collectors on the stack are paused when not
54 # the top, and resumed when they become the top again. 55 # the top, and resumed when they become the top again.
55 _collectors = [] 56 _collectors = []
56 57
57 # The concurrency settings we support here. 58 # The concurrency settings we support here.
58 SUPPORTED_CONCURRENCIES = {"greenlet", "eventlet", "gevent", "thread"} 59 LIGHT_THREADS = {"greenlet", "eventlet", "gevent"}
59 60
60 def __init__( 61 def __init__(
61 self, should_trace, check_include, should_start_context, file_mapper, 62 self, should_trace, check_include, should_start_context, file_mapper,
62 timid, branch, warn, concurrency, 63 timid, branch, warn, concurrency,
63 ): 64 ):
91 and an optional slug argument which will be a string or None, to be 92 and an optional slug argument which will be a string or None, to be
92 used if a warning needs to be issued. 93 used if a warning needs to be issued.
93 94
94 `concurrency` is a list of strings indicating the concurrency libraries 95 `concurrency` is a list of strings indicating the concurrency libraries
95 in use. Valid values are "greenlet", "eventlet", "gevent", or "thread" 96 in use. Valid values are "greenlet", "eventlet", "gevent", or "thread"
96 (the default). Of these four values, only one can be supplied. Other 97 (the default). "thread" can be combined with one of the other three.
97 values are ignored. 98 Other values are ignored.
98 99
99 """ 100 """
100 self.should_trace = should_trace 101 self.should_trace = should_trace
101 self.check_include = check_include 102 self.check_include = check_include
102 self.should_start_context = should_start_context 103 self.should_start_context = should_start_context
103 self.file_mapper = file_mapper 104 self.file_mapper = file_mapper
105 self.branch = branch
104 self.warn = warn 106 self.warn = warn
105 self.branch = branch 107 self.concurrency = concurrency
108 assert isinstance(self.concurrency, list), f"Expected a list: {self.concurrency!r}"
109
106 self.threading = None 110 self.threading = None
107 self.covdata = None 111 self.covdata = None
108
109 self.static_context = None 112 self.static_context = None
110 113
111 self.origin = short_stack() 114 self.origin = short_stack()
112 115
113 self.concur_id_func = None 116 self.concur_id_func = None
114 self.mapped_file_cache = {} 117 self.mapped_file_cache = {}
115
116 # We can handle a few concurrency options here, but only one at a time.
117 these_concurrencies = self.SUPPORTED_CONCURRENCIES.intersection(concurrency)
118 if len(these_concurrencies) > 1:
119 raise CoverageException(f"Conflicting concurrency settings: {concurrency}")
120 self.concurrency = these_concurrencies.pop() if these_concurrencies else ''
121
122 try:
123 if self.concurrency == "greenlet":
124 import greenlet
125 self.concur_id_func = greenlet.getcurrent
126 elif self.concurrency == "eventlet":
127 import eventlet.greenthread # pylint: disable=import-error,useless-suppression
128 self.concur_id_func = eventlet.greenthread.getcurrent
129 elif self.concurrency == "gevent":
130 import gevent # pylint: disable=import-error,useless-suppression
131 self.concur_id_func = gevent.getcurrent
132 elif self.concurrency == "thread" or not self.concurrency:
133 # It's important to import threading only if we need it. If
134 # it's imported early, and the program being measured uses
135 # gevent, then gevent's monkey-patching won't work properly.
136 import threading
137 self.threading = threading
138 else:
139 raise CoverageException(f"Don't understand concurrency={concurrency}")
140 except ImportError as ex:
141 raise CoverageException(
142 "Couldn't trace with concurrency={}, the module isn't installed.".format(
143 self.concurrency,
144 )
145 ) from ex
146
147 self.reset()
148 118
149 if timid: 119 if timid:
150 # Being timid: use the simple Python trace function. 120 # Being timid: use the simple Python trace function.
151 self._trace_class = PyTracer 121 self._trace_class = PyTracer
152 else: 122 else:
160 self.packed_arcs = True 130 self.packed_arcs = True
161 else: 131 else:
162 self.file_disposition_class = FileDisposition 132 self.file_disposition_class = FileDisposition
163 self.supports_plugins = False 133 self.supports_plugins = False
164 self.packed_arcs = False 134 self.packed_arcs = False
135
136 # We can handle a few concurrency options here, but only one at a time.
137 concurrencies = set(self.concurrency)
138 unknown = concurrencies - CoverageConfig.CONCURRENCY_CHOICES
139 if unknown:
140 show = ", ".join(sorted(unknown))
141 raise ConfigError(f"Unknown concurrency choices: {show}")
142 light_threads = concurrencies & self.LIGHT_THREADS
143 if len(light_threads) > 1:
144 show = ", ".join(sorted(light_threads))
145 raise ConfigError(f"Conflicting concurrency settings: {show}")
146 do_threading = False
147
148 try:
149 if "greenlet" in concurrencies:
150 tried = "greenlet"
151 import greenlet
152 self.concur_id_func = greenlet.getcurrent
153 elif "eventlet" in concurrencies:
154 tried = "eventlet"
155 import eventlet.greenthread # pylint: disable=import-error,useless-suppression
156 self.concur_id_func = eventlet.greenthread.getcurrent
157 elif "gevent" in concurrencies:
158 tried = "gevent"
159 import gevent # pylint: disable=import-error,useless-suppression
160 self.concur_id_func = gevent.getcurrent
161
162 if "thread" in concurrencies:
163 do_threading = True
164 except ImportError as ex:
165 msg = f"Couldn't trace with concurrency={tried}, the module isn't installed."
166 raise ConfigError(msg) from ex
167
168 if self.concur_id_func and not hasattr(self._trace_class, "concur_id_func"):
169 raise ConfigError(
170 "Can't support concurrency={} with {}, only threads are supported.".format(
171 tried, self.tracer_name(),
172 )
173 )
174
175 if do_threading or not concurrencies:
176 # It's important to import threading only if we need it. If
177 # it's imported early, and the program being measured uses
178 # gevent, then gevent's monkey-patching won't work properly.
179 import threading
180 self.threading = threading
181
182 self.reset()
165 183
166 def __repr__(self): 184 def __repr__(self):
167 return f"<Collector at 0x{id(self):x}: {self.tracer_name()}>" 185 return f"<Collector at 0x{id(self):x}: {self.tracer_name()}>"
168 186
169 def use_data(self, covdata, context): 187 def use_data(self, covdata, context):
242 tracer.should_trace_cache = self.should_trace_cache 260 tracer.should_trace_cache = self.should_trace_cache
243 tracer.warn = self.warn 261 tracer.warn = self.warn
244 262
245 if hasattr(tracer, 'concur_id_func'): 263 if hasattr(tracer, 'concur_id_func'):
246 tracer.concur_id_func = self.concur_id_func 264 tracer.concur_id_func = self.concur_id_func
247 elif self.concur_id_func:
248 raise CoverageException(
249 "Can't support concurrency={} with {}, only threads are supported".format(
250 self.concurrency, self.tracer_name(),
251 )
252 )
253
254 if hasattr(tracer, 'file_tracers'): 265 if hasattr(tracer, 'file_tracers'):
255 tracer.file_tracers = self.file_tracers 266 tracer.file_tracers = self.file_tracers
256 if hasattr(tracer, 'threading'): 267 if hasattr(tracer, 'threading'):
257 tracer.threading = self.threading 268 tracer.threading = self.threading
258 if hasattr(tracer, 'check_include'): 269 if hasattr(tracer, 'check_include'):

eric ide

mercurial