From cb17b350caf9e113b7a3a36c5add5d16a88ea46d Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Wed, 20 Aug 2014 09:47:21 -0400 Subject: Rename extensions to plugins, since extensions reminds me of parts of filenames --HG-- rename : coverage/extension.py => coverage/plugin.py --- coverage/collector.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'coverage/collector.py') diff --git a/coverage/collector.py b/coverage/collector.py index 546525d2..675758d0 100644 --- a/coverage/collector.py +++ b/coverage/collector.py @@ -47,9 +47,9 @@ class PyTracer(object): self.should_trace = None self.should_trace_cache = None self.warn = None - self.extensions = None + self.plugins = None - self.extension = None + self.plugin = None self.cur_tracename = None # TODO: This is only maintained for the if0 debugging output. Get rid of it eventually. self.cur_file_data = None self.last_line = 0 @@ -112,7 +112,7 @@ class PyTracer(object): if self.coroutine_id_func: self.data_stack = self.data_stacks[self.coroutine_id_func()] self.last_coroutine = self.coroutine_id_func() - self.data_stack.append((self.extension, self.cur_tracename, self.cur_file_data, self.last_line)) + self.data_stack.append((self.plugin, self.cur_tracename, self.cur_file_data, self.last_line)) filename = frame.f_code.co_filename disp = self.should_trace_cache.get(filename) if disp is None: @@ -121,16 +121,16 @@ class PyTracer(object): #print("called, stack is %d deep, tracename is %r" % ( # len(self.data_stack), tracename)) tracename = disp.filename - if tracename and disp.extension: - tracename = disp.extension.file_name(frame) + if tracename and disp.plugin: + tracename = disp.plugin.file_name(frame) if tracename: if tracename not in self.data: self.data[tracename] = {} - if disp.extension: - self.extensions[tracename] = disp.extension.__name__ + if disp.plugin: + self.plugins[tracename] = disp.plugin.__name__ self.cur_tracename = tracename self.cur_file_data = self.data[tracename] - self.extension = disp.extension + self.plugin = disp.plugin else: self.cur_file_data = None # Set the last_line to -1 because the next arc will be entering a @@ -142,8 +142,8 @@ class PyTracer(object): this_coroutine = self.coroutine_id_func() if self.last_coroutine != this_coroutine: print("mismatch: {0} != {1}".format(self.last_coroutine, this_coroutine)) - if self.extension: - lineno_from, lineno_to = self.extension.line_number_range(frame) + if self.plugin: + lineno_from, lineno_to = self.plugin.line_number_range(frame) else: lineno_from, lineno_to = frame.f_lineno, frame.f_lineno if lineno_from != -1: @@ -164,7 +164,7 @@ class PyTracer(object): if self.coroutine_id_func: self.data_stack = self.data_stacks[self.coroutine_id_func()] self.last_coroutine = self.coroutine_id_func() - self.extension, _, self.cur_file_data, self.last_line = self.data_stack.pop() + self.plugin, _, self.cur_file_data, self.last_line = self.data_stack.pop() #print("returned, stack is %d deep" % (len(self.data_stack))) elif event == 'exception': #print("exc", self.last_line, frame.f_lineno) @@ -281,7 +281,7 @@ class Collector(object): # or mapping filenames to dicts with linenumber pairs as keys. self.data = {} - self.extensions = {} + self.plugins = {} # A cache of the results from should_trace, the decision about whether # to trace execution in a file. A dict of filename to (filename or @@ -301,8 +301,8 @@ class Collector(object): tracer.warn = self.warn if hasattr(tracer, 'coroutine_id_func'): tracer.coroutine_id_func = self.coroutine_id_func - if hasattr(tracer, 'extensions'): - tracer.extensions = self.extensions + if hasattr(tracer, 'plugins'): + tracer.plugins = self.plugins fn = tracer.start() self.tracers.append(tracer) return fn @@ -420,5 +420,5 @@ class Collector(object): else: return {} - def get_extension_data(self): - return self.extensions + def get_plugin_data(self): + return self.plugins -- cgit v1.2.1 From 0891e02eb490494ee40a7f840e4ab9fd6b3d2d7b Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 6 Sep 2014 14:24:15 -0400 Subject: Move dispositions closer to useful plugins --- coverage/collector.py | 75 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 30 deletions(-) (limited to 'coverage/collector.py') diff --git a/coverage/collector.py b/coverage/collector.py index 675758d0..26de3727 100644 --- a/coverage/collector.py +++ b/coverage/collector.py @@ -47,12 +47,12 @@ class PyTracer(object): self.should_trace = None self.should_trace_cache = None self.warn = None - self.plugins = None + self.plugin_data = None + + self.plugin = [] + self.cur_file_dict = [] + self.last_line = [0] - self.plugin = None - self.cur_tracename = None # TODO: This is only maintained for the if0 debugging output. Get rid of it eventually. - self.cur_file_data = None - self.last_line = 0 self.data_stack = [] self.data_stacks = collections.defaultdict(list) self.last_exc_back = None @@ -92,18 +92,18 @@ class PyTracer(object): for ident, data_stacks in self.data_stacks.items() ) , width=250) - pprint.pprint(sorted((self.cur_file_data or {}).keys()), width=250) + pprint.pprint(sorted((self.cur_file_dict or {}).keys()), width=250) print("TRYING: {}".format(sorted(next((v for k,v in self.data.items() if k.endswith("try_it.py")), {}).keys()))) - if self.last_exc_back: + if self.last_exc_back: # TODO: bring this up to speed if frame == self.last_exc_back: # Someone forgot a return event. - if self.arcs and self.cur_file_data: + if self.arcs and self.cur_file_dict: pair = (self.last_line, -self.last_exc_firstlineno) - self.cur_file_data[pair] = None + self.cur_file_dict[pair] = None if self.coroutine_id_func: self.data_stack = self.data_stacks[self.coroutine_id_func()] - self.handler, _, self.cur_file_data, self.last_line = self.data_stack.pop() + self.plugin, self.cur_file_dict, self.last_line = self.data_stack.pop() self.last_exc_back = None if event == 'call': @@ -112,7 +112,7 @@ class PyTracer(object): if self.coroutine_id_func: self.data_stack = self.data_stacks[self.coroutine_id_func()] self.last_coroutine = self.coroutine_id_func() - self.data_stack.append((self.plugin, self.cur_tracename, self.cur_file_data, self.last_line)) + self.data_stack.append((self.plugin, self.cur_file_dict, self.last_line)) filename = frame.f_code.co_filename disp = self.should_trace_cache.get(filename) if disp is None: @@ -120,19 +120,26 @@ class PyTracer(object): self.should_trace_cache[filename] = disp #print("called, stack is %d deep, tracename is %r" % ( # len(self.data_stack), tracename)) - tracename = disp.filename - if tracename and disp.plugin: - tracename = disp.plugin.file_name(frame) + self.plugin = None + self.cur_file_dict = None + if disp.trace: + tracename = disp.source_filename + if disp.plugin: + dyn_func = disp.plugin.dynamic_source_file_name() + if dyn_func: + tracename = dyn_func(tracename, frame) + if tracename: + if not self.check_include(tracename): + tracename = None + else: + tracename = None if tracename: if tracename not in self.data: self.data[tracename] = {} if disp.plugin: - self.plugins[tracename] = disp.plugin.__name__ - self.cur_tracename = tracename - self.cur_file_data = self.data[tracename] + self.plugin_data[tracename] = disp.plugin.__name__ + self.cur_file_dict = self.data[tracename] self.plugin = disp.plugin - else: - self.cur_file_data = None # Set the last_line to -1 because the next arc will be entering a # code block, indicated by (-1, n). self.last_line = -1 @@ -142,29 +149,30 @@ class PyTracer(object): this_coroutine = self.coroutine_id_func() if self.last_coroutine != this_coroutine: print("mismatch: {0} != {1}".format(self.last_coroutine, this_coroutine)) + if self.plugin: lineno_from, lineno_to = self.plugin.line_number_range(frame) else: lineno_from, lineno_to = frame.f_lineno, frame.f_lineno if lineno_from != -1: - if self.cur_file_data is not None: + if self.cur_file_dict is not None: if self.arcs: #print("lin", self.last_line, frame.f_lineno) - self.cur_file_data[(self.last_line, lineno_from)] = None + self.cur_file_dict[(self.last_line, lineno_from)] = None else: #print("lin", frame.f_lineno) for lineno in range(lineno_from, lineno_to+1): - self.cur_file_data[lineno] = None + self.cur_file_dict[lineno] = None self.last_line = lineno_to elif event == 'return': - if self.arcs and self.cur_file_data: + if self.arcs and self.cur_file_dict: first = frame.f_code.co_firstlineno - self.cur_file_data[(self.last_line, -first)] = None + self.cur_file_dict[(self.last_line, -first)] = None # Leaving this function, pop the filename stack. if self.coroutine_id_func: self.data_stack = self.data_stacks[self.coroutine_id_func()] self.last_coroutine = self.coroutine_id_func() - self.plugin, _, self.cur_file_data, self.last_line = self.data_stack.pop() + self.plugin, self.cur_file_dict, self.last_line = self.data_stack.pop() #print("returned, stack is %d deep" % (len(self.data_stack))) elif event == 'exception': #print("exc", self.last_line, frame.f_lineno) @@ -224,13 +232,15 @@ class Collector(object): # the top, and resumed when they become the top again. _collectors = [] - def __init__(self, should_trace, timid, branch, warn, coroutine): + def __init__(self, should_trace, check_include, timid, branch, warn, coroutine): """Create a collector. `should_trace` is a function, taking a filename, and returning a canonicalized filename, or None depending on whether the file should be traced or not. + TODO: `check_include` + If `timid` is true, then a slower simpler trace function will be used. This is important for some environments where manipulation of tracing functions make the faster more sophisticated trace function not @@ -243,10 +253,14 @@ class Collector(object): `warn` is a warning function, taking a single string message argument, to be used if a warning needs to be issued. + TODO: `coroutine` + """ self.should_trace = should_trace + self.check_include = check_include self.warn = warn self.branch = branch + if coroutine == "greenlet": import greenlet self.coroutine_id_func = greenlet.getcurrent @@ -258,6 +272,7 @@ class Collector(object): self.coroutine_id_func = gevent.getcurrent else: self.coroutine_id_func = None + self.reset() if timid: @@ -281,7 +296,7 @@ class Collector(object): # or mapping filenames to dicts with linenumber pairs as keys. self.data = {} - self.plugins = {} + self.plugin_data = {} # A cache of the results from should_trace, the decision about whether # to trace execution in a file. A dict of filename to (filename or @@ -301,8 +316,8 @@ class Collector(object): tracer.warn = self.warn if hasattr(tracer, 'coroutine_id_func'): tracer.coroutine_id_func = self.coroutine_id_func - if hasattr(tracer, 'plugins'): - tracer.plugins = self.plugins + if hasattr(tracer, 'plugin_data'): + tracer.plugin_data = self.plugin_data fn = tracer.start() self.tracers.append(tracer) return fn @@ -421,4 +436,4 @@ class Collector(object): return {} def get_plugin_data(self): - return self.plugins + return self.plugin_data -- cgit v1.2.1 From 8b3265d3482baf285fe1061ff285f73f2a818b26 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Wed, 17 Sep 2014 20:17:09 -0400 Subject: Gevent, etc, support finally works. #149 --- coverage/collector.py | 66 +++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 36 deletions(-) (limited to 'coverage/collector.py') diff --git a/coverage/collector.py b/coverage/collector.py index 26de3727..e44b7410 100644 --- a/coverage/collector.py +++ b/coverage/collector.py @@ -1,6 +1,6 @@ """Raw data collector for Coverage.""" -import collections, os, sys, threading +import collections, os, sys try: # Use the C extension code when we can, for speed. @@ -48,6 +48,8 @@ class PyTracer(object): self.should_trace_cache = None self.warn = None self.plugin_data = None + # The threading module to use, if any. + self.threading = None self.plugin = [] self.cur_file_dict = [] @@ -62,39 +64,19 @@ class PyTracer(object): self.coroutine_id_func = None self.last_coroutine = None + def __repr__(self): + return "".format( + id(self), + sum(len(v) for v in self.data.values()), + len(self.data), + ) + def _trace(self, frame, event, arg_unused): """The trace function passed to sys.settrace.""" if self.stopped: return - if 0: - # A lot of debugging to try to understand why gevent isn't right. - import os.path, pprint - def short_ident(ident): - return "{}:{:06X}".format(ident.__class__.__name__, id(ident) & 0xFFFFFF) - - ident = None - if self.coroutine_id_func: - ident = short_ident(self.coroutine_id_func()) - sys.stdout.write("trace event: %s %s %r @%d\n" % ( - event, ident, frame.f_code.co_filename, frame.f_lineno - )) - pprint.pprint( - dict( - ( - short_ident(ident), - [ - (os.path.basename(tn or ""), sorted((cfd or {}).keys()), ll) - for ex, tn, cfd, ll in data_stacks - ] - ) - for ident, data_stacks in self.data_stacks.items() - ) - , width=250) - pprint.pprint(sorted((self.cur_file_dict or {}).keys()), width=250) - print("TRYING: {}".format(sorted(next((v for k,v in self.data.items() if k.endswith("try_it.py")), {}).keys()))) - if self.last_exc_back: # TODO: bring this up to speed if frame == self.last_exc_back: # Someone forgot a return event. @@ -186,14 +168,15 @@ class PyTracer(object): Return a Python function suitable for use with sys.settrace(). """ - self.thread = threading.currentThread() + if self.threading: + self.thread = self.threading.currentThread() sys.settrace(self._trace) return self._trace def stop(self): """Stop this Tracer.""" self.stopped = True - if self.thread != threading.currentThread(): + if self.threading and self.thread != self.threading.currentThread(): # Called on a different thread than started us: we can't unhook # ourseves, but we've set the flag that we should stop, so we won't # do any more tracing. @@ -203,7 +186,7 @@ class PyTracer(object): if sys.gettrace() != self._trace: msg = "Trace function changed, measurement is likely wrong: %r" self.warn(msg % (sys.gettrace(),)) - #print("Stopping tracer on %s" % threading.current_thread().ident) + sys.settrace(None) def get_stats(self): @@ -260,6 +243,7 @@ class Collector(object): self.check_include = check_include self.warn = warn self.branch = branch + self.threading = None if coroutine == "greenlet": import greenlet @@ -271,7 +255,12 @@ class Collector(object): import gevent self.coroutine_id_func = gevent.getcurrent else: + # It's important to import threading only if we need it. If it's + # imported early, and the program being measured uses gevent, then + # gevent's monkey-patching won't work properly. + import threading self.coroutine_id_func = None + self.threading = threading self.reset() @@ -318,6 +307,8 @@ class Collector(object): tracer.coroutine_id_func = self.coroutine_id_func if hasattr(tracer, 'plugin_data'): tracer.plugin_data = self.plugin_data + if hasattr(tracer, 'threading'): + tracer.threading = self.threading fn = tracer.start() self.tracers.append(tracer) return fn @@ -346,7 +337,6 @@ class Collector(object): if self._collectors: self._collectors[-1].pause() self._collectors.append(self) - #print("Started: %r" % self._collectors, file=sys.stderr) # Check to see whether we had a fullcoverage tracer installed. traces0 = [] @@ -371,11 +361,11 @@ class Collector(object): # Install our installation tracer in threading, to jump start other # threads. - threading.settrace(self._installation_trace) + if self.threading: + self.threading.settrace(self._installation_trace) def stop(self): """Stop collecting trace information.""" - #print >>sys.stderr, "Stopping: %r" % self._collectors assert self._collectors assert self._collectors[-1] is self @@ -397,13 +387,17 @@ class Collector(object): print("\nCoverage.py tracer stats:") for k in sorted(stats.keys()): print("%16s: %s" % (k, stats[k])) - threading.settrace(None) + if self.threading: + self.threading.settrace(None) def resume(self): """Resume tracing after a `pause`.""" for tracer in self.tracers: tracer.start() - threading.settrace(self._installation_trace) + if self.threading: + self.threading.settrace(self._installation_trace) + else: + self._start_tracer() def get_line_data(self): """Return the line data collected. -- cgit v1.2.1 From 3617d1a30c87e1c7a4d244106b8cd5ca2d98c80d Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Wed, 17 Sep 2014 20:20:04 -0400 Subject: Remove more commented-out code. #274. --- coverage/collector.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'coverage/collector.py') diff --git a/coverage/collector.py b/coverage/collector.py index e44b7410..4caf6363 100644 --- a/coverage/collector.py +++ b/coverage/collector.py @@ -100,8 +100,7 @@ class PyTracer(object): if disp is None: disp = self.should_trace(filename, frame) self.should_trace_cache[filename] = disp - #print("called, stack is %d deep, tracename is %r" % ( - # len(self.data_stack), tracename)) + self.plugin = None self.cur_file_dict = None if disp.trace: @@ -139,10 +138,8 @@ class PyTracer(object): if lineno_from != -1: if self.cur_file_dict is not None: if self.arcs: - #print("lin", self.last_line, frame.f_lineno) self.cur_file_dict[(self.last_line, lineno_from)] = None else: - #print("lin", frame.f_lineno) for lineno in range(lineno_from, lineno_to+1): self.cur_file_dict[lineno] = None self.last_line = lineno_to @@ -155,9 +152,7 @@ class PyTracer(object): self.data_stack = self.data_stacks[self.coroutine_id_func()] self.last_coroutine = self.coroutine_id_func() self.plugin, self.cur_file_dict, self.last_line = self.data_stack.pop() - #print("returned, stack is %d deep" % (len(self.data_stack))) elif event == 'exception': - #print("exc", self.last_line, frame.f_lineno) self.last_exc_back = frame.f_back self.last_exc_firstlineno = frame.f_code.co_firstlineno return self._trace -- cgit v1.2.1 From 808e6e33222ac39b97b053a1ddde38e3ad782ad6 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 19 Sep 2014 06:47:14 -0400 Subject: Split this into two files, as it should have been years ago. --HG-- rename : coverage/collector.py => coverage/pytracer.py --- coverage/collector.py | 172 +------------------------------------------------- 1 file changed, 3 insertions(+), 169 deletions(-) (limited to 'coverage/collector.py') diff --git a/coverage/collector.py b/coverage/collector.py index 4caf6363..9505c6c9 100644 --- a/coverage/collector.py +++ b/coverage/collector.py @@ -1,6 +1,8 @@ """Raw data collector for Coverage.""" -import collections, os, sys +import os, sys + +from coverage.pytracer import PyTracer try: # Use the C extension code when we can, for speed. @@ -21,174 +23,6 @@ except ImportError: CTracer = None -class PyTracer(object): - """Python implementation of the raw data tracer.""" - - # Because of poor implementations of trace-function-manipulating tools, - # the Python trace function must be kept very simple. In particular, there - # must be only one function ever set as the trace function, both through - # sys.settrace, and as the return value from the trace function. Put - # another way, the trace function must always return itself. It cannot - # swap in other functions, or return None to avoid tracing a particular - # frame. - # - # The trace manipulator that introduced this restriction is DecoratorTools, - # which sets a trace function, and then later restores the pre-existing one - # by calling sys.settrace with a function it found in the current frame. - # - # Systems that use DecoratorTools (or similar trace manipulations) must use - # PyTracer to get accurate results. The command-line --timid argument is - # used to force the use of this tracer. - - def __init__(self): - # Attributes set from the collector: - self.data = None - self.arcs = False - self.should_trace = None - self.should_trace_cache = None - self.warn = None - self.plugin_data = None - # The threading module to use, if any. - self.threading = None - - self.plugin = [] - self.cur_file_dict = [] - self.last_line = [0] - - self.data_stack = [] - self.data_stacks = collections.defaultdict(list) - self.last_exc_back = None - self.last_exc_firstlineno = 0 - self.thread = None - self.stopped = False - self.coroutine_id_func = None - self.last_coroutine = None - - def __repr__(self): - return "".format( - id(self), - sum(len(v) for v in self.data.values()), - len(self.data), - ) - - def _trace(self, frame, event, arg_unused): - """The trace function passed to sys.settrace.""" - - if self.stopped: - return - - if self.last_exc_back: # TODO: bring this up to speed - if frame == self.last_exc_back: - # Someone forgot a return event. - if self.arcs and self.cur_file_dict: - pair = (self.last_line, -self.last_exc_firstlineno) - self.cur_file_dict[pair] = None - if self.coroutine_id_func: - self.data_stack = self.data_stacks[self.coroutine_id_func()] - self.plugin, self.cur_file_dict, self.last_line = self.data_stack.pop() - self.last_exc_back = None - - if event == 'call': - # Entering a new function context. Decide if we should trace - # in this file. - if self.coroutine_id_func: - self.data_stack = self.data_stacks[self.coroutine_id_func()] - self.last_coroutine = self.coroutine_id_func() - self.data_stack.append((self.plugin, self.cur_file_dict, self.last_line)) - filename = frame.f_code.co_filename - disp = self.should_trace_cache.get(filename) - if disp is None: - disp = self.should_trace(filename, frame) - self.should_trace_cache[filename] = disp - - self.plugin = None - self.cur_file_dict = None - if disp.trace: - tracename = disp.source_filename - if disp.plugin: - dyn_func = disp.plugin.dynamic_source_file_name() - if dyn_func: - tracename = dyn_func(tracename, frame) - if tracename: - if not self.check_include(tracename): - tracename = None - else: - tracename = None - if tracename: - if tracename not in self.data: - self.data[tracename] = {} - if disp.plugin: - self.plugin_data[tracename] = disp.plugin.__name__ - self.cur_file_dict = self.data[tracename] - self.plugin = disp.plugin - # Set the last_line to -1 because the next arc will be entering a - # code block, indicated by (-1, n). - self.last_line = -1 - elif event == 'line': - # Record an executed line. - if 0 and self.coroutine_id_func: - this_coroutine = self.coroutine_id_func() - if self.last_coroutine != this_coroutine: - print("mismatch: {0} != {1}".format(self.last_coroutine, this_coroutine)) - - if self.plugin: - lineno_from, lineno_to = self.plugin.line_number_range(frame) - else: - lineno_from, lineno_to = frame.f_lineno, frame.f_lineno - if lineno_from != -1: - if self.cur_file_dict is not None: - if self.arcs: - self.cur_file_dict[(self.last_line, lineno_from)] = None - else: - for lineno in range(lineno_from, lineno_to+1): - self.cur_file_dict[lineno] = None - self.last_line = lineno_to - elif event == 'return': - if self.arcs and self.cur_file_dict: - first = frame.f_code.co_firstlineno - self.cur_file_dict[(self.last_line, -first)] = None - # Leaving this function, pop the filename stack. - if self.coroutine_id_func: - self.data_stack = self.data_stacks[self.coroutine_id_func()] - self.last_coroutine = self.coroutine_id_func() - self.plugin, self.cur_file_dict, self.last_line = self.data_stack.pop() - elif event == 'exception': - self.last_exc_back = frame.f_back - self.last_exc_firstlineno = frame.f_code.co_firstlineno - return self._trace - - def start(self): - """Start this Tracer. - - Return a Python function suitable for use with sys.settrace(). - - """ - if self.threading: - self.thread = self.threading.currentThread() - sys.settrace(self._trace) - return self._trace - - def stop(self): - """Stop this Tracer.""" - self.stopped = True - if self.threading and self.thread != self.threading.currentThread(): - # Called on a different thread than started us: we can't unhook - # ourseves, but we've set the flag that we should stop, so we won't - # do any more tracing. - return - - if hasattr(sys, "gettrace") and self.warn: - if sys.gettrace() != self._trace: - msg = "Trace function changed, measurement is likely wrong: %r" - self.warn(msg % (sys.gettrace(),)) - - sys.settrace(None) - - def get_stats(self): - """Return a dictionary of statistics, or None.""" - return None - - class Collector(object): """Collects trace data. -- cgit v1.2.1 From 3f672471a52a115fd747bb9b02dbc6f08605cf35 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 20 Sep 2014 08:39:40 -0400 Subject: Coroutines are now only supported with the C tracer, and better error handling --- coverage/collector.py | 63 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 18 deletions(-) (limited to 'coverage/collector.py') diff --git a/coverage/collector.py b/coverage/collector.py index 9505c6c9..dccd797e 100644 --- a/coverage/collector.py +++ b/coverage/collector.py @@ -2,6 +2,7 @@ import os, sys +from coverage.misc import CoverageException from coverage.pytracer import PyTracer try: @@ -44,7 +45,9 @@ class Collector(object): # the top, and resumed when they become the top again. _collectors = [] - def __init__(self, should_trace, check_include, timid, branch, warn, coroutine): + def __init__(self, + should_trace, check_include, timid, branch, warn, coroutine, + ): """Create a collector. `should_trace` is a function, taking a filename, and returning a @@ -73,23 +76,35 @@ class Collector(object): self.warn = warn self.branch = branch self.threading = None - - if coroutine == "greenlet": - import greenlet - self.coroutine_id_func = greenlet.getcurrent - elif coroutine == "eventlet": - import eventlet.greenthread - self.coroutine_id_func = eventlet.greenthread.getcurrent - elif coroutine == "gevent": - import gevent - self.coroutine_id_func = gevent.getcurrent - else: - # It's important to import threading only if we need it. If it's - # imported early, and the program being measured uses gevent, then - # gevent's monkey-patching won't work properly. - import threading - self.coroutine_id_func = None - self.threading = threading + self.coroutine = coroutine + + self.coroutine_id_func = None + + try: + if coroutine == "greenlet": + import greenlet + self.coroutine_id_func = greenlet.getcurrent + elif coroutine == "eventlet": + import eventlet.greenthread + self.coroutine_id_func = eventlet.greenthread.getcurrent + elif coroutine == "gevent": + import gevent + self.coroutine_id_func = gevent.getcurrent + elif coroutine == "thread" or not coroutine: + # It's important to import threading only if we need it. If + # it's imported early, and the program being measured uses + # gevent, then gevent's monkey-patching won't work properly. + import threading + self.threading = threading + else: + raise CoverageException( + "Don't understand coroutine=%s" % coroutine + ) + except ImportError: + raise CoverageException( + "Couldn't trace with coroutine=%s, " + "the module isn't installed." % coroutine + ) self.reset() @@ -101,6 +116,7 @@ class Collector(object): # trace function. self._trace_class = CTracer or PyTracer + def __repr__(self): return "" % id(self) @@ -132,14 +148,25 @@ class Collector(object): tracer.should_trace = self.should_trace tracer.should_trace_cache = self.should_trace_cache tracer.warn = self.warn + if hasattr(tracer, 'coroutine_id_func'): tracer.coroutine_id_func = self.coroutine_id_func + elif self.coroutine_id_func: + raise CoverageException( + "Can't support coroutine=%s with %s, " + "only threads are supported" % ( + self.coroutine, self.tracer_name(), + ) + ) + if hasattr(tracer, 'plugin_data'): tracer.plugin_data = self.plugin_data if hasattr(tracer, 'threading'): tracer.threading = self.threading + fn = tracer.start() self.tracers.append(tracer) + return fn # The trace function has to be set individually on each thread before -- cgit v1.2.1 From a57e1ca1fc50217cdbf1860d4bc8cf402a8522bb Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 20 Sep 2014 13:11:50 -0400 Subject: More things we don't need with the latest versions --- coverage/collector.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'coverage/collector.py') diff --git a/coverage/collector.py b/coverage/collector.py index dccd797e..8ff4db2c 100644 --- a/coverage/collector.py +++ b/coverage/collector.py @@ -196,12 +196,11 @@ class Collector(object): # Check to see whether we had a fullcoverage tracer installed. traces0 = [] - if hasattr(sys, "gettrace"): - fn0 = sys.gettrace() - if fn0: - tracer0 = getattr(fn0, '__self__', None) - if tracer0: - traces0 = getattr(tracer0, 'traces', []) + fn0 = sys.gettrace() + if fn0: + tracer0 = getattr(fn0, '__self__', None) + if tracer0: + traces0 = getattr(tracer0, 'traces', []) # Install the tracer on this thread. fn = self._start_tracer() -- cgit v1.2.1 From dfe7ffcb773c972864a35811b4a0b316b7b97e03 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 20 Sep 2014 20:29:24 -0400 Subject: More metacov, tox, and make cleanup --- coverage/collector.py | 1 - 1 file changed, 1 deletion(-) (limited to 'coverage/collector.py') diff --git a/coverage/collector.py b/coverage/collector.py index 8ff4db2c..85c8dc90 100644 --- a/coverage/collector.py +++ b/coverage/collector.py @@ -116,7 +116,6 @@ class Collector(object): # trace function. self._trace_class = CTracer or PyTracer - def __repr__(self): return "" % id(self) -- cgit v1.2.1