diff --git a/CHANGES.rst b/CHANGES.rst index 81e02732a..95b34a774 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -23,12 +23,18 @@ This list is detailed and covers changes in each pre-release version. Unreleased ---------- -- When sorting human-readable names, numeric components are sorted correctly: - file10.py will appear after file9.py. This applies to file names, module - names, environment variables, and test contexts. +- Feature: Coverage now sets an environment variable, ``COVERAGE_RUN`` when + running your code with the ``coverage run`` command. The value is not + important, and may change in the future. Closes `issue 553`_. -- Branch coverage measurement is faster, though you might only notice on - code that is executed many times, such as long-running loops. +- Fix: When sorting human-readable names, numeric components are sorted + correctly: file10.py will appear after file9.py. This applies to file names, + module names, environment variables, and test contexts. + +- Performance: Branch coverage measurement is faster, though you might only + notice on code that is executed many times, such as long-running loops. + + .. _issue 553: https://github.com/nedbat/coveragepy/issues/553 .. _changes_602: diff --git a/coverage/cmdline.py b/coverage/cmdline.py index dfdbd1c71..5f972035f 100644 --- a/coverage/cmdline.py +++ b/coverage/cmdline.py @@ -6,6 +6,7 @@ import glob import optparse # pylint: disable=deprecated-module +import os import os.path import shlex import sys @@ -739,6 +740,8 @@ def do_run(self, options, args): ) return ERR + os.environ["COVERAGE_RUN"] = "true" + runner = PyRunner(args, as_module=bool(options.module)) runner.prepare() diff --git a/coverage/version.py b/coverage/version.py index 8aa3bcf72..2b96b696c 100644 --- a/coverage/version.py +++ b/coverage/version.py @@ -5,7 +5,7 @@ # This file is exec'ed in setup.py, don't import anything! # Same semantics as sys.version_info. -version_info = (6, 0, 3, "alpha", 0) +version_info = (6, 1, 0, "alpha", 0) def _make_version(major, minor, micro, releaselevel, serial): diff --git a/doc/cmd.rst b/doc/cmd.rst index b4bf41ab3..1a54043d1 100644 --- a/doc/cmd.rst +++ b/doc/cmd.rst @@ -137,6 +137,10 @@ If your coverage results seem to be overlooking code that you know has been executed, try running coverage.py again with the ``--timid`` flag. This uses a simpler but slower trace method, and might be needed in rare cases. +Coverage.py sets an environment variable, ``COVERAGE_RUN`` to indicate that +your code is running under coverage measurement. The value is not relevant, +and may change in the future. + .. _cmd_warnings: diff --git a/tests/helpers.py b/tests/helpers.py index c85a36cb4..1420bed7e 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -24,6 +24,12 @@ def run_command(cmd): Returns the exit status code and the combined stdout and stderr. """ + # Subprocesses are expensive, but convenient, and so may be over-used in + # the test suite. Use these lines to get a list of the tests using them: + if 0: # pragma: debugging + with open("/tmp/processes.txt", "a") as proctxt: + print(os.environ.get("PYTEST_CURRENT_TEST", "unknown"), file=proctxt, flush=True) + # In some strange cases (PyPy3 in a virtualenv!?) the stdout encoding of # the subprocess is set incorrectly to ascii. Use an environment variable # to force the encoding to be the same as ours. diff --git a/tests/test_process.py b/tests/test_process.py index a31350498..29ce6071b 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -39,7 +39,7 @@ def test_save_on_exit(self): self.run_command("coverage run mycode.py") self.assert_exists(".coverage") - def test_environment(self): + def test_tests_dir_is_importable(self): # Checks that we can import modules from the tests directory at all! self.make_file("mycode.py", """\ import covmod1 @@ -53,6 +53,21 @@ def test_environment(self): self.assert_exists(".coverage") assert out == 'done\n' + def test_coverage_run_envvar_is_in_coveragerun(self): + # Test that we are setting COVERAGE_RUN when we run. + self.make_file("envornot.py", """\ + import os + print(os.environ.get("COVERAGE_RUN", "nope")) + """) + self.del_environ("COVERAGE_RUN") + # Regular Python doesn't have the environment variable. + out = self.run_command("python envornot.py") + assert out == "nope\n" + self.del_environ("COVERAGE_RUN") + # But `coverage run` does have it. + out = self.run_command("coverage run envornot.py") + assert out == "true\n" + def make_b_or_c_py(self): """Create b_or_c.py, used in a few of these tests.""" # "b_or_c.py b" will run 6 lines. @@ -263,7 +278,6 @@ def test_combine_parallel_data_keep(self): self.assert_exists(".coverage") self.assert_file_count(".coverage.*", 2) - def test_append_data(self): self.make_b_or_c_py() @@ -830,6 +844,10 @@ def foo(): def test_module_name(self): # https://github.com/nedbat/coveragepy/issues/478 + # Make sure help doesn't show a silly command name when run as a + # module, like it used to: + # $ python -m coverage + # Code coverage for Python. Use '__main__.py help' for help. out = self.run_command("python -m coverage") assert "Use 'coverage help' for help" in out