Exemple #1
0
def test_source_for_file(tmpdir):
    path = tmpdir.join("a.py")
    src = str(path)
    assert source_for_file(src) == src
    assert source_for_file(src + 'c') == src
    assert source_for_file(src + 'o') == src
    unknown = src + 'FOO'
    assert source_for_file(unknown) == unknown
Exemple #2
0
def test_source_for_file_windows(tmpdir):
    path = tmpdir.join("a.py")
    src = str(path)

    # On windows if a pyw exists, it is an acceptable source
    path_windows = tmpdir.ensure("a.pyw")
    assert str(path_windows) == source_for_file(src + 'c')

    # If both pyw and py exist, py is preferred
    path.ensure(file=True)
    assert source_for_file(src + 'c') == src
Exemple #3
0
    def _post_save_work(self):
        """After saving data, look for warnings, post-work, etc.

        Warn about things that should have happened but didn't.
        Look for unexecuted files.

        """
        # If there are still entries in the source_pkgs_unmatched list,
        # then we never encountered those packages.
        if self._warn_unimported_source:
            for pkg in self.source_pkgs_unmatched:
                self._warn_about_unmeasured_code(pkg)

        # Find out if we got any data.
        if not self.data and self._warn_no_data:
            self._warn("No data was collected.", slug="no-data-collected")

        # Find files that were never executed at all.
        for pkg in self.source_pkgs:
            if (not pkg in sys.modules or
                not hasattr(sys.modules[pkg], '__file__') or
                not os.path.exists(sys.modules[pkg].__file__)):
                continue
            pkg_file = source_for_file(sys.modules[pkg].__file__)
            self._find_unexecuted_files(self._canonical_path(pkg_file))

        for src in self.source:
            self._find_unexecuted_files(src)

        if self.config.note:
            self.data.add_run_info(note=self.config.note)
Exemple #4
0
    def _post_save_work(self):
        """After saving data, look for warnings, post-work, etc.

        Warn about things that should have happened but didn't.
        Look for unexecuted files.

        """
        # If there are still entries in the source_pkgs_unmatched list,
        # then we never encountered those packages.
        if self._warn_unimported_source:
            for pkg in self.source_pkgs_unmatched:
                self._warn_about_unmeasured_code(pkg)

        # Find out if we got any data.
        if not self.data and self._warn_no_data:
            self._warn("No data was collected.", slug="no-data-collected")

        # Find files that were never executed at all.
        for pkg in self.source_pkgs:
            if (not pkg in sys.modules or
                not hasattr(sys.modules[pkg], '__file__') or
                not os.path.exists(sys.modules[pkg].__file__)):
                continue
            pkg_file = source_for_file(sys.modules[pkg].__file__)
            self._find_unexecuted_files(self._canonical_path(pkg_file))

        for src in self.source:
            self._find_unexecuted_files(src)

        if self.config.note:
            self.data.add_run_info(note=self.config.note)
Exemple #5
0
    def get_data(self):
        """Get the collected data and reset the collector.

        Also warn about various problems collecting data.

        Returns a :class:`coverage.CoverageData`, the collected coverage data.

        .. versionadded:: 4.0

        """
        self._init()
        if not self._measured:
            return self.data

        self.collector.save_data(self.data)

        # If there are still entries in the source_pkgs_unmatched list,
        # then we never encountered those packages.
        if self._warn_unimported_source:
            for pkg in self.source_pkgs_unmatched:
                if pkg not in sys.modules:
                    self._warn("Module %s was never imported." % pkg)
                elif not (hasattr(sys.modules[pkg], '__file__')
                          and os.path.exists(sys.modules[pkg].__file__)):
                    self._warn("Module %s has no Python source." % pkg)
                else:
                    self._warn(
                        "Module %s was previously imported, but not measured."
                        % pkg)

        # Find out if we got any data.
        if not self.data and self._warn_no_data:
            self._warn("No data was collected.")

        # Find files that were never executed at all.
        for pkg in self.source_pkgs:
            if (not pkg in sys.modules
                    or not hasattr(sys.modules[pkg], '__file__')
                    or not os.path.exists(sys.modules[pkg].__file__)):
                continue
            pkg_file = source_for_file(sys.modules[pkg].__file__)

            if not pkg_file.endswith('__init__.py'):
                # We only want to explore the source tree of packages.
                # For instance if pkg_file is /lib/python2.7/site-packages/args.pyc,
                # we do not want to explore all of /lib/python2.7/site-packages.
                continue
            self._find_unexecuted_files(self._canonical_dir(pkg_file))

        for src in self.source:
            self._find_unexecuted_files(src)

        if self.config.note:
            self.data.add_run_info(note=self.config.note)

        self._measured = False
        return self.data
    def get_data(self):
        """Get the collected data and reset the collector.

        Also warn about various problems collecting data.

        Returns a :class:`coverage.CoverageData`, the collected coverage data.

        .. versionadded:: 4.0

        """
        self._init()
        if not self._measured:
            return self.data

        self.collector.save_data(self.data)

        # If there are still entries in the source_pkgs_unmatched list,
        # then we never encountered those packages.
        if self._warn_unimported_source:
            for pkg in self.source_pkgs_unmatched:
                if pkg not in sys.modules:
                    self._warn("Module %s was never imported." % pkg)
                elif not (
                    hasattr(sys.modules[pkg], '__file__') and
                    os.path.exists(sys.modules[pkg].__file__)
                ):
                    self._warn("Module %s has no Python source." % pkg)
                else:
                    self._warn("Module %s was previously imported, but not measured." % pkg)

        # Find out if we got any data.
        if not self.data and self._warn_no_data:
            self._warn("No data was collected.")

        # Find files that were never executed at all.
        for pkg in self.source_pkgs:
            if (not pkg in sys.modules or
                not hasattr(sys.modules[pkg], '__file__') or
                not os.path.exists(sys.modules[pkg].__file__)):
                continue
            pkg_file = source_for_file(sys.modules[pkg].__file__)

            if not pkg_file.endswith('__init__.py'):
                # We only want to explore the source tree of packages.
                # For instance if pkg_file is /lib/python2.7/site-packages/args.pyc,
                # we do not want to explore all of /lib/python2.7/site-packages.
                continue
            self._find_unexecuted_files(self._canonical_dir(pkg_file))

        for src in self.source:
            self._find_unexecuted_files(src)

        if self.config.note:
            self.data.add_run_info(note=self.config.note)

        self._measured = False
        return self.data
Exemple #7
0
    def find_unexecuted_files(self):
        for pkg in self.source_pkgs:
            if (not pkg in sys.modules
                    or not hasattr(sys.modules[pkg], '__file__')
                    or not os.path.exists(sys.modules[pkg].__file__)):
                continue
            pkg_file = source_for_file(sys.modules[pkg].__file__)
            for ret in self._find_unexecuted_files(canonical_path(pkg_file)):
                yield ret

        for src in self.source:
            for ret in self._find_unexecuted_files(src):
                yield ret
Exemple #8
0
    def find_possibly_unexecuted_files(self):
        """Find files in the areas of interest that might be untraced.

        Yields pairs: file path, and responsible plug-in name.
        """
        for pkg in self.source_pkgs:
            if (not pkg in sys.modules
                    or not module_has_file(sys.modules[pkg])):
                continue
            pkg_file = source_for_file(sys.modules[pkg].__file__)
            yield from self._find_executable_files(canonical_path(pkg_file))

        for src in self.source:
            yield from self._find_executable_files(src)
Exemple #9
0
    def find_unexecuted_files(self):
        """Find files in the areas of interest that weren't traced.

        Yields pairs: file path, and responsible plug-in name.
        """
        for pkg in self.source_pkgs:
            if (not pkg in sys.modules or
                not module_has_file(sys.modules[pkg])):
                continue
            pkg_file = source_for_file(sys.modules[pkg].__file__)
            for ret in self._find_unexecuted_files(canonical_path(pkg_file)):
                yield ret

        for src in self.source:
            for ret in self._find_unexecuted_files(src):
                yield ret
Exemple #10
0
    def should_trace(self, filename, frame=None):
        """Decide whether to trace execution in `filename`, with a reason.

        This function is called from the trace function.  As each new file name
        is encountered, this function determines whether it is traced or not.

        Returns a FileDisposition object.

        """
        original_filename = filename
        disp = disposition_init(self.disp_class, filename)

        def nope(disp, reason):
            """Simple helper to make it easy to return NO."""
            disp.trace = False
            disp.reason = reason
            return disp

        if frame is not None:
            # Compiled Python files have two file names: frame.f_code.co_filename is
            # the file name at the time the .pyc was compiled.  The second name is
            # __file__, which is where the .pyc was actually loaded from.  Since
            # .pyc files can be moved after compilation (for example, by being
            # installed), we look for __file__ in the frame and prefer it to the
            # co_filename value.
            dunder_file = frame.f_globals and frame.f_globals.get('__file__')
            if dunder_file:
                filename = source_for_file(dunder_file)
                if original_filename and not original_filename.startswith('<'):
                    orig = os.path.basename(original_filename)
                    if orig != os.path.basename(filename):
                        # Files shouldn't be renamed when moved. This happens when
                        # exec'ing code.  If it seems like something is wrong with
                        # the frame's file name, then just use the original.
                        filename = original_filename

        if not filename:
            # Empty string is pretty useless.
            return nope(disp, "empty string isn't a file name")

        if filename.startswith('memory:'):
            return nope(disp, "memory isn't traceable")

        if filename.startswith('<'):
            # Lots of non-file execution is represented with artificial
            # file names like "<string>", "<doctest readme.txt[0]>", or
            # "<exec_function>".  Don't ever trace these executions, since we
            # can't do anything with the data later anyway.
            return nope(disp, "not a real file name")

        # pyexpat does a dumb thing, calling the trace function explicitly from
        # C code with a C file name.
        if re.search(r"[/\\]Modules[/\\]pyexpat.c", filename):
            return nope(disp, "pyexpat lies about itself")

        # Jython reports the .class file to the tracer, use the source file.
        if filename.endswith("$py.class"):
            filename = filename[:-9] + ".py"

        canonical = canonical_filename(filename)
        disp.canonical_filename = canonical

        # Try the plugins, see if they have an opinion about the file.
        plugin = None
        for plugin in self.plugins.file_tracers:
            if not plugin._coverage_enabled:
                continue

            try:
                file_tracer = plugin.file_tracer(canonical)
                if file_tracer is not None:
                    file_tracer._coverage_plugin = plugin
                    disp.trace = True
                    disp.file_tracer = file_tracer
                    if file_tracer.has_dynamic_source_filename():
                        disp.has_dynamic_filename = True
                    else:
                        disp.source_filename = canonical_filename(
                            file_tracer.source_filename()
                        )
                    break
            except Exception:
                self.warn(
                    "Disabling plug-in %r due to an exception:" % (plugin._coverage_plugin_name)
                )
                traceback.print_exc()
                plugin._coverage_enabled = False
                continue
        else:
            # No plugin wanted it: it's Python.
            disp.trace = True
            disp.source_filename = canonical

        if not disp.has_dynamic_filename:
            if not disp.source_filename:
                raise CoverageException(
                    "Plugin %r didn't set source_filename for %r" %
                    (plugin, disp.original_filename)
                )
            reason = self.check_include_omit_etc(disp.source_filename, frame)
            if reason:
                nope(disp, reason)

        return disp
Exemple #11
0
    def _should_trace_internal(self, filename, frame):
        """Decide whether to trace execution in `filename`, with a reason.

        This function is called from the trace function.  As each new file name
        is encountered, this function determines whether it is traced or not.

        Returns a FileDisposition object.

        """
        original_filename = filename
        disp = _disposition_init(self.collector.file_disposition_class, filename)

        def nope(disp, reason):
            """Simple helper to make it easy to return NO."""
            disp.trace = False
            disp.reason = reason
            return disp

        # Compiled Python files have two file names: frame.f_code.co_filename is
        # the file name at the time the .pyc was compiled.  The second name is
        # __file__, which is where the .pyc was actually loaded from.  Since
        # .pyc files can be moved after compilation (for example, by being
        # installed), we look for __file__ in the frame and prefer it to the
        # co_filename value.
        dunder_file = frame.f_globals and frame.f_globals.get('__file__')
        if dunder_file:
            filename = source_for_file(dunder_file)
            if original_filename and not original_filename.startswith('<'):
                orig = os.path.basename(original_filename)
                if orig != os.path.basename(filename):
                    # Files shouldn't be renamed when moved. This happens when
                    # exec'ing code.  If it seems like something is wrong with
                    # the frame's file name, then just use the original.
                    filename = original_filename

        if not filename:
            # Empty string is pretty useless.
            return nope(disp, "empty string isn't a file name")

        if filename.startswith('memory:'):
            return nope(disp, "memory isn't traceable")

        if filename.startswith('<'):
            # Lots of non-file execution is represented with artificial
            # file names like "<string>", "<doctest readme.txt[0]>", or
            # "<exec_function>".  Don't ever trace these executions, since we
            # can't do anything with the data later anyway.
            return nope(disp, "not a real file name")

        # pyexpat does a dumb thing, calling the trace function explicitly from
        # C code with a C file name.
        if re.search(r"[/\\]Modules[/\\]pyexpat.c", filename):
            return nope(disp, "pyexpat lies about itself")

        # Jython reports the .class file to the tracer, use the source file.
        if filename.endswith("$py.class"):
            filename = filename[:-9] + ".py"

        canonical = canonical_filename(filename)
        disp.canonical_filename = canonical

        # Try the plugins, see if they have an opinion about the file.
        plugin = None
        for plugin in self.plugins.file_tracers:
            if not plugin._coverage_enabled:
                continue

            try:
                file_tracer = plugin.file_tracer(canonical)
                if file_tracer is not None:
                    file_tracer._coverage_plugin = plugin
                    disp.trace = True
                    disp.file_tracer = file_tracer
                    if file_tracer.has_dynamic_source_filename():
                        disp.has_dynamic_filename = True
                    else:
                        disp.source_filename = canonical_filename(
                            file_tracer.source_filename()
                        )
                    break
            except Exception:
                self._warn(
                    "Disabling plug-in %r due to an exception:" % (
                        plugin._coverage_plugin_name
                    )
                )
                traceback.print_exc()
                plugin._coverage_enabled = False
                continue
        else:
            # No plugin wanted it: it's Python.
            disp.trace = True
            disp.source_filename = canonical

        if not disp.has_dynamic_filename:
            if not disp.source_filename:
                raise CoverageException(
                    "Plugin %r didn't set source_filename for %r" %
                    (plugin, disp.original_filename)
                )
            reason = self._check_include_omit_etc_internal(
                disp.source_filename, frame,
            )
            if reason:
                nope(disp, reason)

        return disp
Exemple #12
0
def test_source_for_file_jython():
    assert source_for_file("a$py.class") == "a.py"
Exemple #13
0
def test_source_for_file_jython():
    assert source_for_file("a$py.class") == "a.py"