Skip to content

Commit

Permalink
Don't import anything before start(). Fixes #909.
Browse files Browse the repository at this point in the history
  • Loading branch information
nedbat committed Jan 3, 2020
1 parent 7541b4f commit caf6cd1
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 21 deletions.
6 changes: 6 additions & 0 deletions CHANGES.rst
Expand Up @@ -30,6 +30,11 @@ Unreleased
information about the config files read now shows absolute paths to the
files.

- When running programs as modules (with ``-m``), some measured modules were
imported before coverage starts. This resulted in unwanted warnings
("Already imported a file that will be measured") and a reduction in coverage
totals, described in `issue 909`_. This is now fixed.

- The handling of source files with non-encodable file names has changed.
Previously, if a file name could not be encoded as UTF-8, an error occurred,
as described in `issue 891`_. Now, those files will not be measured, since
Expand All @@ -45,6 +50,7 @@ Unreleased
.. _issue 891: https://github.com/nedbat/coveragepy/issues/891
.. _issue 901: https://github.com/nedbat/coveragepy/issues/901
.. _issue 907: https://github.com/nedbat/coveragepy/issues/907
.. _issue 909: https://github.com/nedbat/coveragepy/issues/909


.. _changes_501:
Expand Down
52 changes: 31 additions & 21 deletions coverage/execfile.py
Expand Up @@ -116,21 +116,45 @@ def __init__(self, args, as_module=False):
self.package = self.modulename = self.pathname = self.loader = self.spec = None

def prepare(self):
"""Do initial preparation to run Python code.
Includes finding the module to run, adjusting sys.argv[0], and changing
sys.path to match what Python does.
"""Set sys.path properly.
This needs to happen before any importing, and without importing anything.
"""
should_update_sys_path = True

if self.as_module:
if env.PYBEHAVIOR.actual_syspath0_dash_m:
path0 = os.getcwd()
else:
path0 = ""
sys.path[0] = path0
should_update_sys_path = False
elif os.path.isdir(self.arg0):
# Running a directory means running the __main__.py file in that
# directory.
path0 = self.arg0
else:
path0 = os.path.abspath(os.path.dirname(self.arg0))


if should_update_sys_path:
# sys.path fakery. If we are being run as a command, then sys.path[0]
# is the directory of the "coverage" script. If this is so, replace
# sys.path[0] with the directory of the file we're running, or the
# current directory when running modules. If it isn't so, then we
# don't know what's going on, and just leave it alone.
top_file = inspect.stack()[-1][0].f_code.co_filename
if os.path.abspath(sys.path[0]) == os.path.abspath(os.path.dirname(top_file)):
# Set sys.path correctly.
sys.path[0] = python_reported_file(path0)

def _prepare2(self):
"""Do more preparation to run Python code.
Includes finding the module to run and adjusting sys.argv[0].
This method is allowed to import code.
"""
if self.as_module:
self.modulename = self.arg0
pathname, self.package, self.spec = find_module(self.modulename)
if self.spec is not None:
Expand All @@ -141,7 +165,6 @@ def prepare(self):
elif os.path.isdir(self.arg0):
# Running a directory means running the __main__.py file in that
# directory.
path0 = self.arg0
for ext in [".py", ".pyc", ".pyo"]:
try_filename = os.path.join(self.arg0, "__main__" + ext)
if os.path.exists(try_filename):
Expand All @@ -165,29 +188,16 @@ def prepare(self):
self.package = ""
self.loader = DummyLoader("__main__")
else:
path0 = os.path.abspath(os.path.dirname(self.arg0))
if env.PY3:
self.loader = DummyLoader("__main__")

self.arg0 = python_reported_file(self.arg0)

if self.modulename is None:
self.modulename = '__main__'

if should_update_sys_path:
# sys.path fakery. If we are being run as a command, then sys.path[0]
# is the directory of the "coverage" script. If this is so, replace
# sys.path[0] with the directory of the file we're running, or the
# current directory when running modules. If it isn't so, then we
# don't know what's going on, and just leave it alone.
top_file = inspect.stack()[-1][0].f_code.co_filename
if os.path.abspath(sys.path[0]) == os.path.abspath(os.path.dirname(top_file)):
# Set sys.path correctly.
sys.path[0] = python_reported_file(path0)

def run(self):
"""Run the Python code!"""

self._prepare2()

# Create a module to serve as __main__
main_mod = types.ModuleType('__main__')

Expand Down

0 comments on commit caf6cd1

Please sign in to comment.