1# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
3
4"""Core control stuff for coverage.py."""
5
6import atexit
7import inspect
8import os
9import platform
10import re
11import sys
12import traceback
13
14from coverage import env, files
15from coverage.annotate import AnnotateReporter
16from coverage.backward import string_class, iitems
17from coverage.collector import Collector
18from coverage.config import CoverageConfig
19from coverage.data import CoverageData, CoverageDataFiles
20from coverage.debug import DebugControl
21from coverage.files import TreeMatcher, FnmatchMatcher
22from coverage.files import PathAliases, find_python_files, prep_patterns
23from coverage.files import ModuleMatcher, abs_file
24from coverage.html import HtmlReporter
25from coverage.misc import CoverageException, bool_or_none, join_regex
26from coverage.misc import file_be_gone, isolate_module
27from coverage.monkey import patch_multiprocessing
28from coverage.plugin import FileReporter
29from coverage.plugin_support import Plugins
30from coverage.python import PythonFileReporter
31from coverage.results import Analysis, Numbers
32from coverage.summary import SummaryReporter
33from coverage.xmlreport import XmlReporter
34
35os = isolate_module(os)
36
37# Pypy has some unusual stuff in the "stdlib".  Consider those locations
38# when deciding where the stdlib is.
39try:
40    import _structseq
41except ImportError:
42    _structseq = None
43
44
45class Coverage(object):
46    """Programmatic access to coverage.py.
47
48    To use::
49
50        from coverage import Coverage
51
52        cov = Coverage()
53        cov.start()
54        #.. call your code ..
55        cov.stop()
56        cov.html_report(directory='covhtml')
57
58    """
59    def __init__(
60        self, data_file=None, data_suffix=None, cover_pylib=None,
61        auto_data=False, timid=None, branch=None, config_file=True,
62        source=None, omit=None, include=None, debug=None,
63        concurrency=None,
64    ):
65        """
66        `data_file` is the base name of the data file to use, defaulting to
67        ".coverage".  `data_suffix` is appended (with a dot) to `data_file` to
68        create the final file name.  If `data_suffix` is simply True, then a
69        suffix is created with the machine and process identity included.
70
71        `cover_pylib` is a boolean determining whether Python code installed
72        with the Python interpreter is measured.  This includes the Python
73        standard library and any packages installed with the interpreter.
74
75        If `auto_data` is true, then any existing data file will be read when
76        coverage measurement starts, and data will be saved automatically when
77        measurement stops.
78
79        If `timid` is true, then a slower and simpler trace function will be
80        used.  This is important for some environments where manipulation of
81        tracing functions breaks the faster trace function.
82
83        If `branch` is true, then branch coverage will be measured in addition
84        to the usual statement coverage.
85
86        `config_file` determines what configuration file to read:
87
88            * If it is ".coveragerc", it is interpreted as if it were True,
89              for backward compatibility.
90
91            * If it is a string, it is the name of the file to read.  If the
92              file can't be read, it is an error.
93
94            * If it is True, then a few standard files names are tried
95              (".coveragerc", "setup.cfg").  It is not an error for these files
96              to not be found.
97
98            * If it is False, then no configuration file is read.
99
100        `source` is a list of file paths or package names.  Only code located
101        in the trees indicated by the file paths or package names will be
102        measured.
103
104        `include` and `omit` are lists of file name patterns. Files that match
105        `include` will be measured, files that match `omit` will not.  Each
106        will also accept a single string argument.
107
108        `debug` is a list of strings indicating what debugging information is
109        desired.
110
111        `concurrency` is a string indicating the concurrency library being used
112        in the measured code.  Without this, coverage.py will get incorrect
113        results.  Valid strings are "greenlet", "eventlet", "gevent", or
114        "thread" (the default).
115
116        .. versionadded:: 4.0
117            The `concurrency` parameter.
118
119        """
120        # Build our configuration from a number of sources:
121        # 1: defaults:
122        self.config = CoverageConfig()
123
124        # 2: from the rcfile, .coveragerc or setup.cfg file:
125        if config_file:
126            did_read_rc = False
127            # Some API users were specifying ".coveragerc" to mean the same as
128            # True, so make it so.
129            if config_file == ".coveragerc":
130                config_file = True
131            specified_file = (config_file is not True)
132            if not specified_file:
133                config_file = ".coveragerc"
134
135            did_read_rc = self.config.from_file(config_file)
136
137            if not did_read_rc:
138                if specified_file:
139                    raise CoverageException(
140                        "Couldn't read '%s' as a config file" % config_file
141                        )
142                self.config.from_file("setup.cfg", section_prefix="coverage:")
143
144        # 3: from environment variables:
145        env_data_file = os.environ.get('COVERAGE_FILE')
146        if env_data_file:
147            self.config.data_file = env_data_file
148        debugs = os.environ.get('COVERAGE_DEBUG')
149        if debugs:
150            self.config.debug.extend(debugs.split(","))
151
152        # 4: from constructor arguments:
153        self.config.from_args(
154            data_file=data_file, cover_pylib=cover_pylib, timid=timid,
155            branch=branch, parallel=bool_or_none(data_suffix),
156            source=source, omit=omit, include=include, debug=debug,
157            concurrency=concurrency,
158            )
159
160        self._debug_file = None
161        self._auto_data = auto_data
162        self._data_suffix = data_suffix
163
164        # The matchers for _should_trace.
165        self.source_match = None
166        self.source_pkgs_match = None
167        self.pylib_match = self.cover_match = None
168        self.include_match = self.omit_match = None
169
170        # Is it ok for no data to be collected?
171        self._warn_no_data = True
172        self._warn_unimported_source = True
173
174        # A record of all the warnings that have been issued.
175        self._warnings = []
176
177        # Other instance attributes, set later.
178        self.omit = self.include = self.source = None
179        self.source_pkgs = None
180        self.data = self.data_files = self.collector = None
181        self.plugins = None
182        self.pylib_dirs = self.cover_dirs = None
183        self.data_suffix = self.run_suffix = None
184        self._exclude_re = None
185        self.debug = None
186
187        # State machine variables:
188        # Have we initialized everything?
189        self._inited = False
190        # Have we started collecting and not stopped it?
191        self._started = False
192        # Have we measured some data and not harvested it?
193        self._measured = False
194
195    def _init(self):
196        """Set all the initial state.
197
198        This is called by the public methods to initialize state. This lets us
199        construct a :class:`Coverage` object, then tweak its state before this
200        function is called.
201
202        """
203        if self._inited:
204            return
205
206        # Create and configure the debugging controller. COVERAGE_DEBUG_FILE
207        # is an environment variable, the name of a file to append debug logs
208        # to.
209        if self._debug_file is None:
210            debug_file_name = os.environ.get("COVERAGE_DEBUG_FILE")
211            if debug_file_name:
212                self._debug_file = open(debug_file_name, "a")
213            else:
214                self._debug_file = sys.stderr
215        self.debug = DebugControl(self.config.debug, self._debug_file)
216
217        # Load plugins
218        self.plugins = Plugins.load_plugins(self.config.plugins, self.config, self.debug)
219
220        # _exclude_re is a dict that maps exclusion list names to compiled
221        # regexes.
222        self._exclude_re = {}
223        self._exclude_regex_stale()
224
225        files.set_relative_directory()
226
227        # The source argument can be directories or package names.
228        self.source = []
229        self.source_pkgs = []
230        for src in self.config.source or []:
231            if os.path.exists(src):
232                self.source.append(files.canonical_filename(src))
233            else:
234                self.source_pkgs.append(src)
235
236        self.omit = prep_patterns(self.config.omit)
237        self.include = prep_patterns(self.config.include)
238
239        concurrency = self.config.concurrency
240        if concurrency == "multiprocessing":
241            patch_multiprocessing()
242            concurrency = None
243
244        self.collector = Collector(
245            should_trace=self._should_trace,
246            check_include=self._check_include_omit_etc,
247            timid=self.config.timid,
248            branch=self.config.branch,
249            warn=self._warn,
250            concurrency=concurrency,
251            )
252
253        # Early warning if we aren't going to be able to support plugins.
254        if self.plugins.file_tracers and not self.collector.supports_plugins:
255            self._warn(
256                "Plugin file tracers (%s) aren't supported with %s" % (
257                    ", ".join(
258                        plugin._coverage_plugin_name
259                            for plugin in self.plugins.file_tracers
260                        ),
261                    self.collector.tracer_name(),
262                    )
263                )
264            for plugin in self.plugins.file_tracers:
265                plugin._coverage_enabled = False
266
267        # Suffixes are a bit tricky.  We want to use the data suffix only when
268        # collecting data, not when combining data.  So we save it as
269        # `self.run_suffix` now, and promote it to `self.data_suffix` if we
270        # find that we are collecting data later.
271        if self._data_suffix or self.config.parallel:
272            if not isinstance(self._data_suffix, string_class):
273                # if data_suffix=True, use .machinename.pid.random
274                self._data_suffix = True
275        else:
276            self._data_suffix = None
277        self.data_suffix = None
278        self.run_suffix = self._data_suffix
279
280        # Create the data file.  We do this at construction time so that the
281        # data file will be written into the directory where the process
282        # started rather than wherever the process eventually chdir'd to.
283        self.data = CoverageData(debug=self.debug)
284        self.data_files = CoverageDataFiles(basename=self.config.data_file, warn=self._warn)
285
286        # The directories for files considered "installed with the interpreter".
287        self.pylib_dirs = set()
288        if not self.config.cover_pylib:
289            # Look at where some standard modules are located. That's the
290            # indication for "installed with the interpreter". In some
291            # environments (virtualenv, for example), these modules may be
292            # spread across a few locations. Look at all the candidate modules
293            # we've imported, and take all the different ones.
294            for m in (atexit, inspect, os, platform, re, _structseq, traceback):
295                if m is not None and hasattr(m, "__file__"):
296                    self.pylib_dirs.add(self._canonical_dir(m))
297            if _structseq and not hasattr(_structseq, '__file__'):
298                # PyPy 2.4 has no __file__ in the builtin modules, but the code
299                # objects still have the file names.  So dig into one to find
300                # the path to exclude.
301                structseq_new = _structseq.structseq_new
302                try:
303                    structseq_file = structseq_new.func_code.co_filename
304                except AttributeError:
305                    structseq_file = structseq_new.__code__.co_filename
306                self.pylib_dirs.add(self._canonical_dir(structseq_file))
307
308        # To avoid tracing the coverage.py code itself, we skip anything
309        # located where we are.
310        self.cover_dirs = [self._canonical_dir(__file__)]
311        if env.TESTING:
312            # When testing, we use PyContracts, which should be considered
313            # part of coverage.py, and it uses six. Exclude those directories
314            # just as we exclude ourselves.
315            import contracts, six
316            for mod in [contracts, six]:
317                self.cover_dirs.append(self._canonical_dir(mod))
318
319        # Set the reporting precision.
320        Numbers.set_precision(self.config.precision)
321
322        atexit.register(self._atexit)
323
324        self._inited = True
325
326        # Create the matchers we need for _should_trace
327        if self.source or self.source_pkgs:
328            self.source_match = TreeMatcher(self.source)
329            self.source_pkgs_match = ModuleMatcher(self.source_pkgs)
330        else:
331            if self.cover_dirs:
332                self.cover_match = TreeMatcher(self.cover_dirs)
333            if self.pylib_dirs:
334                self.pylib_match = TreeMatcher(self.pylib_dirs)
335        if self.include:
336            self.include_match = FnmatchMatcher(self.include)
337        if self.omit:
338            self.omit_match = FnmatchMatcher(self.omit)
339
340        # The user may want to debug things, show info if desired.
341        wrote_any = False
342        if self.debug.should('config'):
343            config_info = sorted(self.config.__dict__.items())
344            self.debug.write_formatted_info("config", config_info)
345            wrote_any = True
346
347        if self.debug.should('sys'):
348            self.debug.write_formatted_info("sys", self.sys_info())
349            for plugin in self.plugins:
350                header = "sys: " + plugin._coverage_plugin_name
351                info = plugin.sys_info()
352                self.debug.write_formatted_info(header, info)
353            wrote_any = True
354
355        if wrote_any:
356            self.debug.write_formatted_info("end", ())
357
358    def _canonical_dir(self, morf):
359        """Return the canonical directory of the module or file `morf`."""
360        morf_filename = PythonFileReporter(morf, self).filename
361        return os.path.split(morf_filename)[0]
362
363    def _source_for_file(self, filename):
364        """Return the source file for `filename`.
365
366        Given a file name being traced, return the best guess as to the source
367        file to attribute it to.
368
369        """
370        if filename.endswith(".py"):
371            # .py files are themselves source files.
372            return filename
373
374        elif filename.endswith((".pyc", ".pyo")):
375            # Bytecode files probably have source files near them.
376            py_filename = filename[:-1]
377            if os.path.exists(py_filename):
378                # Found a .py file, use that.
379                return py_filename
380            if env.WINDOWS:
381                # On Windows, it could be a .pyw file.
382                pyw_filename = py_filename + "w"
383                if os.path.exists(pyw_filename):
384                    return pyw_filename
385            # Didn't find source, but it's probably the .py file we want.
386            return py_filename
387
388        elif filename.endswith("$py.class"):
389            # Jython is easy to guess.
390            return filename[:-9] + ".py"
391
392        # No idea, just use the file name as-is.
393        return filename
394
395    def _name_for_module(self, module_globals, filename):
396        """Get the name of the module for a set of globals and file name.
397
398        For configurability's sake, we allow __main__ modules to be matched by
399        their importable name.
400
401        If loaded via runpy (aka -m), we can usually recover the "original"
402        full dotted module name, otherwise, we resort to interpreting the
403        file name to get the module's name.  In the case that the module name
404        can't be determined, None is returned.
405
406        """
407        dunder_name = module_globals.get('__name__', None)
408
409        if isinstance(dunder_name, str) and dunder_name != '__main__':
410            # This is the usual case: an imported module.
411            return dunder_name
412
413        loader = module_globals.get('__loader__', None)
414        for attrname in ('fullname', 'name'):   # attribute renamed in py3.2
415            if hasattr(loader, attrname):
416                fullname = getattr(loader, attrname)
417            else:
418                continue
419
420            if isinstance(fullname, str) and fullname != '__main__':
421                # Module loaded via: runpy -m
422                return fullname
423
424        # Script as first argument to Python command line.
425        inspectedname = inspect.getmodulename(filename)
426        if inspectedname is not None:
427            return inspectedname
428        else:
429            return dunder_name
430
431    def _should_trace_internal(self, filename, frame):
432        """Decide whether to trace execution in `filename`, with a reason.
433
434        This function is called from the trace function.  As each new file name
435        is encountered, this function determines whether it is traced or not.
436
437        Returns a FileDisposition object.
438
439        """
440        original_filename = filename
441        disp = _disposition_init(self.collector.file_disposition_class, filename)
442
443        def nope(disp, reason):
444            """Simple helper to make it easy to return NO."""
445            disp.trace = False
446            disp.reason = reason
447            return disp
448
449        # Compiled Python files have two file names: frame.f_code.co_filename is
450        # the file name at the time the .pyc was compiled.  The second name is
451        # __file__, which is where the .pyc was actually loaded from.  Since
452        # .pyc files can be moved after compilation (for example, by being
453        # installed), we look for __file__ in the frame and prefer it to the
454        # co_filename value.
455        dunder_file = frame.f_globals.get('__file__')
456        if dunder_file:
457            filename = self._source_for_file(dunder_file)
458            if original_filename and not original_filename.startswith('<'):
459                orig = os.path.basename(original_filename)
460                if orig != os.path.basename(filename):
461                    # Files shouldn't be renamed when moved. This happens when
462                    # exec'ing code.  If it seems like something is wrong with
463                    # the frame's file name, then just use the original.
464                    filename = original_filename
465
466        if not filename:
467            # Empty string is pretty useless.
468            return nope(disp, "empty string isn't a file name")
469
470        if filename.startswith('memory:'):
471            return nope(disp, "memory isn't traceable")
472
473        if filename.startswith('<'):
474            # Lots of non-file execution is represented with artificial
475            # file names like "<string>", "<doctest readme.txt[0]>", or
476            # "<exec_function>".  Don't ever trace these executions, since we
477            # can't do anything with the data later anyway.
478            return nope(disp, "not a real file name")
479
480        # pyexpat does a dumb thing, calling the trace function explicitly from
481        # C code with a C file name.
482        if re.search(r"[/\\]Modules[/\\]pyexpat.c", filename):
483            return nope(disp, "pyexpat lies about itself")
484
485        # Jython reports the .class file to the tracer, use the source file.
486        if filename.endswith("$py.class"):
487            filename = filename[:-9] + ".py"
488
489        canonical = files.canonical_filename(filename)
490        disp.canonical_filename = canonical
491
492        # Try the plugins, see if they have an opinion about the file.
493        plugin = None
494        for plugin in self.plugins.file_tracers:
495            if not plugin._coverage_enabled:
496                continue
497
498            try:
499                file_tracer = plugin.file_tracer(canonical)
500                if file_tracer is not None:
501                    file_tracer._coverage_plugin = plugin
502                    disp.trace = True
503                    disp.file_tracer = file_tracer
504                    if file_tracer.has_dynamic_source_filename():
505                        disp.has_dynamic_filename = True
506                    else:
507                        disp.source_filename = files.canonical_filename(
508                            file_tracer.source_filename()
509                        )
510                    break
511            except Exception:
512                self._warn(
513                    "Disabling plugin %r due to an exception:" % (
514                        plugin._coverage_plugin_name
515                    )
516                )
517                traceback.print_exc()
518                plugin._coverage_enabled = False
519                continue
520        else:
521            # No plugin wanted it: it's Python.
522            disp.trace = True
523            disp.source_filename = canonical
524
525        if not disp.has_dynamic_filename:
526            if not disp.source_filename:
527                raise CoverageException(
528                    "Plugin %r didn't set source_filename for %r" %
529                    (plugin, disp.original_filename)
530                )
531            reason = self._check_include_omit_etc_internal(
532                disp.source_filename, frame,
533            )
534            if reason:
535                nope(disp, reason)
536
537        return disp
538
539    def _check_include_omit_etc_internal(self, filename, frame):
540        """Check a file name against the include, omit, etc, rules.
541
542        Returns a string or None.  String means, don't trace, and is the reason
543        why.  None means no reason found to not trace.
544
545        """
546        modulename = self._name_for_module(frame.f_globals, filename)
547
548        # If the user specified source or include, then that's authoritative
549        # about the outer bound of what to measure and we don't have to apply
550        # any canned exclusions. If they didn't, then we have to exclude the
551        # stdlib and coverage.py directories.
552        if self.source_match:
553            if self.source_pkgs_match.match(modulename):
554                if modulename in self.source_pkgs:
555                    self.source_pkgs.remove(modulename)
556                return None  # There's no reason to skip this file.
557
558            if not self.source_match.match(filename):
559                return "falls outside the --source trees"
560        elif self.include_match:
561            if not self.include_match.match(filename):
562                return "falls outside the --include trees"
563        else:
564            # If we aren't supposed to trace installed code, then check if this
565            # is near the Python standard library and skip it if so.
566            if self.pylib_match and self.pylib_match.match(filename):
567                return "is in the stdlib"
568
569            # We exclude the coverage.py code itself, since a little of it
570            # will be measured otherwise.
571            if self.cover_match and self.cover_match.match(filename):
572                return "is part of coverage.py"
573
574        # Check the file against the omit pattern.
575        if self.omit_match and self.omit_match.match(filename):
576            return "is inside an --omit pattern"
577
578        # No reason found to skip this file.
579        return None
580
581    def _should_trace(self, filename, frame):
582        """Decide whether to trace execution in `filename`.
583
584        Calls `_should_trace_internal`, and returns the FileDisposition.
585
586        """
587        disp = self._should_trace_internal(filename, frame)
588        if self.debug.should('trace'):
589            self.debug.write(_disposition_debug_msg(disp))
590        return disp
591
592    def _check_include_omit_etc(self, filename, frame):
593        """Check a file name against the include/omit/etc, rules, verbosely.
594
595        Returns a boolean: True if the file should be traced, False if not.
596
597        """
598        reason = self._check_include_omit_etc_internal(filename, frame)
599        if self.debug.should('trace'):
600            if not reason:
601                msg = "Including %r" % (filename,)
602            else:
603                msg = "Not including %r: %s" % (filename, reason)
604            self.debug.write(msg)
605
606        return not reason
607
608    def _warn(self, msg):
609        """Use `msg` as a warning."""
610        self._warnings.append(msg)
611        if self.debug.should('pid'):
612            msg = "[%d] %s" % (os.getpid(), msg)
613        sys.stderr.write("Coverage.py warning: %s\n" % msg)
614
615    def get_option(self, option_name):
616        """Get an option from the configuration.
617
618        `option_name` is a colon-separated string indicating the section and
619        option name.  For example, the ``branch`` option in the ``[run]``
620        section of the config file would be indicated with `"run:branch"`.
621
622        Returns the value of the option.
623
624        .. versionadded:: 4.0
625
626        """
627        return self.config.get_option(option_name)
628
629    def set_option(self, option_name, value):
630        """Set an option in the configuration.
631
632        `option_name` is a colon-separated string indicating the section and
633        option name.  For example, the ``branch`` option in the ``[run]``
634        section of the config file would be indicated with ``"run:branch"``.
635
636        `value` is the new value for the option.  This should be a Python
637        value where appropriate.  For example, use True for booleans, not the
638        string ``"True"``.
639
640        As an example, calling::
641
642            cov.set_option("run:branch", True)
643
644        has the same effect as this configuration file::
645
646            [run]
647            branch = True
648
649        .. versionadded:: 4.0
650
651        """
652        self.config.set_option(option_name, value)
653
654    def use_cache(self, usecache):
655        """Obsolete method."""
656        self._init()
657        if not usecache:
658            self._warn("use_cache(False) is no longer supported.")
659
660    def load(self):
661        """Load previously-collected coverage data from the data file."""
662        self._init()
663        self.collector.reset()
664        self.data_files.read(self.data)
665
666    def start(self):
667        """Start measuring code coverage.
668
669        Coverage measurement actually occurs in functions called after
670        :meth:`start` is invoked.  Statements in the same scope as
671        :meth:`start` won't be measured.
672
673        Once you invoke :meth:`start`, you must also call :meth:`stop`
674        eventually, or your process might not shut down cleanly.
675
676        """
677        self._init()
678        if self.run_suffix:
679            # Calling start() means we're running code, so use the run_suffix
680            # as the data_suffix when we eventually save the data.
681            self.data_suffix = self.run_suffix
682        if self._auto_data:
683            self.load()
684
685        self.collector.start()
686        self._started = True
687        self._measured = True
688
689    def stop(self):
690        """Stop measuring code coverage."""
691        if self._started:
692            self.collector.stop()
693        self._started = False
694
695    def _atexit(self):
696        """Clean up on process shutdown."""
697        if self._started:
698            self.stop()
699        if self._auto_data:
700            self.save()
701
702    def erase(self):
703        """Erase previously-collected coverage data.
704
705        This removes the in-memory data collected in this session as well as
706        discarding the data file.
707
708        """
709        self._init()
710        self.collector.reset()
711        self.data.erase()
712        self.data_files.erase(parallel=self.config.parallel)
713
714    def clear_exclude(self, which='exclude'):
715        """Clear the exclude list."""
716        self._init()
717        setattr(self.config, which + "_list", [])
718        self._exclude_regex_stale()
719
720    def exclude(self, regex, which='exclude'):
721        """Exclude source lines from execution consideration.
722
723        A number of lists of regular expressions are maintained.  Each list
724        selects lines that are treated differently during reporting.
725
726        `which` determines which list is modified.  The "exclude" list selects
727        lines that are not considered executable at all.  The "partial" list
728        indicates lines with branches that are not taken.
729
730        `regex` is a regular expression.  The regex is added to the specified
731        list.  If any of the regexes in the list is found in a line, the line
732        is marked for special treatment during reporting.
733
734        """
735        self._init()
736        excl_list = getattr(self.config, which + "_list")
737        excl_list.append(regex)
738        self._exclude_regex_stale()
739
740    def _exclude_regex_stale(self):
741        """Drop all the compiled exclusion regexes, a list was modified."""
742        self._exclude_re.clear()
743
744    def _exclude_regex(self, which):
745        """Return a compiled regex for the given exclusion list."""
746        if which not in self._exclude_re:
747            excl_list = getattr(self.config, which + "_list")
748            self._exclude_re[which] = join_regex(excl_list)
749        return self._exclude_re[which]
750
751    def get_exclude_list(self, which='exclude'):
752        """Return a list of excluded regex patterns.
753
754        `which` indicates which list is desired.  See :meth:`exclude` for the
755        lists that are available, and their meaning.
756
757        """
758        self._init()
759        return getattr(self.config, which + "_list")
760
761    def save(self):
762        """Save the collected coverage data to the data file."""
763        self._init()
764        self.get_data()
765        self.data_files.write(self.data, suffix=self.data_suffix)
766
767    def combine(self, data_paths=None):
768        """Combine together a number of similarly-named coverage data files.
769
770        All coverage data files whose name starts with `data_file` (from the
771        coverage() constructor) will be read, and combined together into the
772        current measurements.
773
774        `data_paths` is a list of files or directories from which data should
775        be combined. If no list is passed, then the data files from the
776        directory indicated by the current data file (probably the current
777        directory) will be combined.
778
779        .. versionadded:: 4.0
780            The `data_paths` parameter.
781
782        """
783        self._init()
784        self.get_data()
785
786        aliases = None
787        if self.config.paths:
788            aliases = PathAliases()
789            for paths in self.config.paths.values():
790                result = paths[0]
791                for pattern in paths[1:]:
792                    aliases.add(pattern, result)
793
794        self.data_files.combine_parallel_data(self.data, aliases=aliases, data_paths=data_paths)
795
796    def get_data(self):
797        """Get the collected data and reset the collector.
798
799        Also warn about various problems collecting data.
800
801        Returns a :class:`coverage.CoverageData`, the collected coverage data.
802
803        .. versionadded:: 4.0
804
805        """
806        self._init()
807        if not self._measured:
808            return self.data
809
810        self.collector.save_data(self.data)
811
812        # If there are still entries in the source_pkgs list, then we never
813        # encountered those packages.
814        if self._warn_unimported_source:
815            for pkg in self.source_pkgs:
816                if pkg not in sys.modules:
817                    self._warn("Module %s was never imported." % pkg)
818                elif not (
819                    hasattr(sys.modules[pkg], '__file__') and
820                    os.path.exists(sys.modules[pkg].__file__)
821                ):
822                    self._warn("Module %s has no Python source." % pkg)
823                else:
824                    self._warn("Module %s was previously imported, but not measured." % pkg)
825
826        # Find out if we got any data.
827        if not self.data and self._warn_no_data:
828            self._warn("No data was collected.")
829
830        # Find files that were never executed at all.
831        for src in self.source:
832            for py_file in find_python_files(src):
833                py_file = files.canonical_filename(py_file)
834
835                if self.omit_match and self.omit_match.match(py_file):
836                    # Turns out this file was omitted, so don't pull it back
837                    # in as unexecuted.
838                    continue
839
840                self.data.touch_file(py_file)
841
842        if self.config.note:
843            self.data.add_run_info(note=self.config.note)
844
845        self._measured = False
846        return self.data
847
848    # Backward compatibility with version 1.
849    def analysis(self, morf):
850        """Like `analysis2` but doesn't return excluded line numbers."""
851        f, s, _, m, mf = self.analysis2(morf)
852        return f, s, m, mf
853
854    def analysis2(self, morf):
855        """Analyze a module.
856
857        `morf` is a module or a file name.  It will be analyzed to determine
858        its coverage statistics.  The return value is a 5-tuple:
859
860        * The file name for the module.
861        * A list of line numbers of executable statements.
862        * A list of line numbers of excluded statements.
863        * A list of line numbers of statements not run (missing from
864          execution).
865        * A readable formatted string of the missing line numbers.
866
867        The analysis uses the source file itself and the current measured
868        coverage data.
869
870        """
871        self._init()
872        analysis = self._analyze(morf)
873        return (
874            analysis.filename,
875            sorted(analysis.statements),
876            sorted(analysis.excluded),
877            sorted(analysis.missing),
878            analysis.missing_formatted(),
879            )
880
881    def _analyze(self, it):
882        """Analyze a single morf or code unit.
883
884        Returns an `Analysis` object.
885
886        """
887        self.get_data()
888        if not isinstance(it, FileReporter):
889            it = self._get_file_reporter(it)
890
891        return Analysis(self.data, it)
892
893    def _get_file_reporter(self, morf):
894        """Get a FileReporter for a module or file name."""
895        plugin = None
896        file_reporter = "python"
897
898        if isinstance(morf, string_class):
899            abs_morf = abs_file(morf)
900            plugin_name = self.data.file_tracer(abs_morf)
901            if plugin_name:
902                plugin = self.plugins.get(plugin_name)
903
904        if plugin:
905            file_reporter = plugin.file_reporter(abs_morf)
906            if file_reporter is None:
907                raise CoverageException(
908                    "Plugin %r did not provide a file reporter for %r." % (
909                        plugin._coverage_plugin_name, morf
910                    )
911                )
912
913        if file_reporter == "python":
914            file_reporter = PythonFileReporter(morf, self)
915
916        return file_reporter
917
918    def _get_file_reporters(self, morfs=None):
919        """Get a list of FileReporters for a list of modules or file names.
920
921        For each module or file name in `morfs`, find a FileReporter.  Return
922        the list of FileReporters.
923
924        If `morfs` is a single module or file name, this returns a list of one
925        FileReporter.  If `morfs` is empty or None, then the list of all files
926        measured is used to find the FileReporters.
927
928        """
929        if not morfs:
930            morfs = self.data.measured_files()
931
932        # Be sure we have a list.
933        if not isinstance(morfs, (list, tuple)):
934            morfs = [morfs]
935
936        file_reporters = []
937        for morf in morfs:
938            file_reporter = self._get_file_reporter(morf)
939            file_reporters.append(file_reporter)
940
941        return file_reporters
942
943    def report(
944        self, morfs=None, show_missing=True, ignore_errors=None,
945        file=None,                  # pylint: disable=redefined-builtin
946        omit=None, include=None, skip_covered=False,
947    ):
948        """Write a summary report to `file`.
949
950        Each module in `morfs` is listed, with counts of statements, executed
951        statements, missing statements, and a list of lines missed.
952
953        `include` is a list of file name patterns.  Files that match will be
954        included in the report. Files matching `omit` will not be included in
955        the report.
956
957        Returns a float, the total percentage covered.
958
959        """
960        self.get_data()
961        self.config.from_args(
962            ignore_errors=ignore_errors, omit=omit, include=include,
963            show_missing=show_missing, skip_covered=skip_covered,
964            )
965        reporter = SummaryReporter(self, self.config)
966        return reporter.report(morfs, outfile=file)
967
968    def annotate(
969        self, morfs=None, directory=None, ignore_errors=None,
970        omit=None, include=None,
971    ):
972        """Annotate a list of modules.
973
974        Each module in `morfs` is annotated.  The source is written to a new
975        file, named with a ",cover" suffix, with each line prefixed with a
976        marker to indicate the coverage of the line.  Covered lines have ">",
977        excluded lines have "-", and missing lines have "!".
978
979        See :meth:`report` for other arguments.
980
981        """
982        self.get_data()
983        self.config.from_args(
984            ignore_errors=ignore_errors, omit=omit, include=include
985            )
986        reporter = AnnotateReporter(self, self.config)
987        reporter.report(morfs, directory=directory)
988
989    def html_report(self, morfs=None, directory=None, ignore_errors=None,
990                    omit=None, include=None, extra_css=None, title=None):
991        """Generate an HTML report.
992
993        The HTML is written to `directory`.  The file "index.html" is the
994        overview starting point, with links to more detailed pages for
995        individual modules.
996
997        `extra_css` is a path to a file of other CSS to apply on the page.
998        It will be copied into the HTML directory.
999
1000        `title` is a text string (not HTML) to use as the title of the HTML
1001        report.
1002
1003        See :meth:`report` for other arguments.
1004
1005        Returns a float, the total percentage covered.
1006
1007        """
1008        self.get_data()
1009        self.config.from_args(
1010            ignore_errors=ignore_errors, omit=omit, include=include,
1011            html_dir=directory, extra_css=extra_css, html_title=title,
1012            )
1013        reporter = HtmlReporter(self, self.config)
1014        return reporter.report(morfs)
1015
1016    def xml_report(
1017        self, morfs=None, outfile=None, ignore_errors=None,
1018        omit=None, include=None,
1019    ):
1020        """Generate an XML report of coverage results.
1021
1022        The report is compatible with Cobertura reports.
1023
1024        Each module in `morfs` is included in the report.  `outfile` is the
1025        path to write the file to, "-" will write to stdout.
1026
1027        See :meth:`report` for other arguments.
1028
1029        Returns a float, the total percentage covered.
1030
1031        """
1032        self.get_data()
1033        self.config.from_args(
1034            ignore_errors=ignore_errors, omit=omit, include=include,
1035            xml_output=outfile,
1036            )
1037        file_to_close = None
1038        delete_file = False
1039        if self.config.xml_output:
1040            if self.config.xml_output == '-':
1041                outfile = sys.stdout
1042            else:
1043                # Ensure that the output directory is created; done here
1044                # because this report pre-opens the output file.
1045                # HTMLReport does this using the Report plumbing because
1046                # its task is more complex, being multiple files.
1047                output_dir = os.path.dirname(self.config.xml_output)
1048                if output_dir and not os.path.isdir(output_dir):
1049                    os.makedirs(output_dir)
1050                open_kwargs = {}
1051                if env.PY3:
1052                    open_kwargs['encoding'] = 'utf8'
1053                outfile = open(self.config.xml_output, "w", **open_kwargs)
1054                file_to_close = outfile
1055        try:
1056            reporter = XmlReporter(self, self.config)
1057            return reporter.report(morfs, outfile=outfile)
1058        except CoverageException:
1059            delete_file = True
1060            raise
1061        finally:
1062            if file_to_close:
1063                file_to_close.close()
1064                if delete_file:
1065                    file_be_gone(self.config.xml_output)
1066
1067    def sys_info(self):
1068        """Return a list of (key, value) pairs showing internal information."""
1069
1070        import coverage as covmod
1071
1072        self._init()
1073
1074        ft_plugins = []
1075        for ft in self.plugins.file_tracers:
1076            ft_name = ft._coverage_plugin_name
1077            if not ft._coverage_enabled:
1078                ft_name += " (disabled)"
1079            ft_plugins.append(ft_name)
1080
1081        info = [
1082            ('version', covmod.__version__),
1083            ('coverage', covmod.__file__),
1084            ('cover_dirs', self.cover_dirs),
1085            ('pylib_dirs', self.pylib_dirs),
1086            ('tracer', self.collector.tracer_name()),
1087            ('plugins.file_tracers', ft_plugins),
1088            ('config_files', self.config.attempted_config_files),
1089            ('configs_read', self.config.config_files),
1090            ('data_path', self.data_files.filename),
1091            ('python', sys.version.replace('\n', '')),
1092            ('platform', platform.platform()),
1093            ('implementation', platform.python_implementation()),
1094            ('executable', sys.executable),
1095            ('cwd', os.getcwd()),
1096            ('path', sys.path),
1097            ('environment', sorted(
1098                ("%s = %s" % (k, v))
1099                for k, v in iitems(os.environ)
1100                if k.startswith(("COV", "PY"))
1101            )),
1102            ('command_line', " ".join(getattr(sys, 'argv', ['???']))),
1103            ]
1104
1105        matcher_names = [
1106            'source_match', 'source_pkgs_match',
1107            'include_match', 'omit_match',
1108            'cover_match', 'pylib_match',
1109            ]
1110
1111        for matcher_name in matcher_names:
1112            matcher = getattr(self, matcher_name)
1113            if matcher:
1114                matcher_info = matcher.info()
1115            else:
1116                matcher_info = '-none-'
1117            info.append((matcher_name, matcher_info))
1118
1119        return info
1120
1121
1122# FileDisposition "methods": FileDisposition is a pure value object, so it can
1123# be implemented in either C or Python.  Acting on them is done with these
1124# functions.
1125
1126def _disposition_init(cls, original_filename):
1127    """Construct and initialize a new FileDisposition object."""
1128    disp = cls()
1129    disp.original_filename = original_filename
1130    disp.canonical_filename = original_filename
1131    disp.source_filename = None
1132    disp.trace = False
1133    disp.reason = ""
1134    disp.file_tracer = None
1135    disp.has_dynamic_filename = False
1136    return disp
1137
1138
1139def _disposition_debug_msg(disp):
1140    """Make a nice debug message of what the FileDisposition is doing."""
1141    if disp.trace:
1142        msg = "Tracing %r" % (disp.original_filename,)
1143        if disp.file_tracer:
1144            msg += ": will be traced by %r" % disp.file_tracer
1145    else:
1146        msg = "Not tracing %r: %s" % (disp.original_filename, disp.reason)
1147    return msg
1148
1149
1150def process_startup():
1151    """Call this at Python start-up to perhaps measure coverage.
1152
1153    If the environment variable COVERAGE_PROCESS_START is defined, coverage
1154    measurement is started.  The value of the variable is the config file
1155    to use.
1156
1157    There are two ways to configure your Python installation to invoke this
1158    function when Python starts:
1159
1160    #. Create or append to sitecustomize.py to add these lines::
1161
1162        import coverage
1163        coverage.process_startup()
1164
1165    #. Create a .pth file in your Python installation containing::
1166
1167        import coverage; coverage.process_startup()
1168
1169    """
1170    cps = os.environ.get("COVERAGE_PROCESS_START")
1171    if not cps:
1172        # No request for coverage, nothing to do.
1173        return
1174
1175    # This function can be called more than once in a process. This happens
1176    # because some virtualenv configurations make the same directory visible
1177    # twice in sys.path.  This means that the .pth file will be found twice,
1178    # and executed twice, executing this function twice.  We set a global
1179    # flag (an attribute on this function) to indicate that coverage.py has
1180    # already been started, so we can avoid doing it twice.
1181    #
1182    # https://bitbucket.org/ned/coveragepy/issue/340/keyerror-subpy has more
1183    # details.
1184
1185    if hasattr(process_startup, "done"):
1186        # We've annotated this function before, so we must have already
1187        # started coverage.py in this process.  Nothing to do.
1188        return
1189
1190    process_startup.done = True
1191    cov = Coverage(config_file=cps, auto_data=True)
1192    cov.start()
1193    cov._warn_no_data = False
1194    cov._warn_unimported_source = False
1195