summaryrefslogtreecommitdiffstats
path: root/third_party/python/coverage/igor.py
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/python/coverage/igor.py')
-rw-r--r--third_party/python/coverage/igor.py395
1 files changed, 395 insertions, 0 deletions
diff --git a/third_party/python/coverage/igor.py b/third_party/python/coverage/igor.py
new file mode 100644
index 0000000000..a742cb8e19
--- /dev/null
+++ b/third_party/python/coverage/igor.py
@@ -0,0 +1,395 @@
+# coding: utf-8
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
+
+"""Helper for building, testing, and linting coverage.py.
+
+To get portability, all these operations are written in Python here instead
+of in shell scripts, batch files, or Makefiles.
+
+"""
+
+import contextlib
+import fnmatch
+import glob
+import inspect
+import os
+import platform
+import sys
+import textwrap
+import warnings
+import zipfile
+
+import pytest
+
+
+@contextlib.contextmanager
+def ignore_warnings():
+ """Context manager to ignore warning within the with statement."""
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore")
+ yield
+
+
+# Functions named do_* are executable from the command line: do_blah is run
+# by "python igor.py blah".
+
+
+def do_show_env():
+ """Show the environment variables."""
+ print("Environment:")
+ for env in sorted(os.environ):
+ print(" %s = %r" % (env, os.environ[env]))
+
+
+def do_remove_extension():
+ """Remove the compiled C extension, no matter what its name."""
+
+ so_patterns = """
+ tracer.so
+ tracer.*.so
+ tracer.pyd
+ tracer.*.pyd
+ """.split()
+
+ for pattern in so_patterns:
+ pattern = os.path.join("coverage", pattern)
+ for filename in glob.glob(pattern):
+ try:
+ os.remove(filename)
+ except OSError:
+ pass
+
+
+def label_for_tracer(tracer):
+ """Get the label for these tests."""
+ if tracer == "py":
+ label = "with Python tracer"
+ else:
+ label = "with C tracer"
+
+ return label
+
+
+def should_skip(tracer):
+ """Is there a reason to skip these tests?"""
+ if tracer == "py":
+ # $set_env.py: COVERAGE_NO_PYTRACER - Don't run the tests under the Python tracer.
+ skipper = os.environ.get("COVERAGE_NO_PYTRACER")
+ else:
+ # $set_env.py: COVERAGE_NO_CTRACER - Don't run the tests under the C tracer.
+ skipper = os.environ.get("COVERAGE_NO_CTRACER")
+
+ if skipper:
+ msg = "Skipping tests " + label_for_tracer(tracer)
+ if len(skipper) > 1:
+ msg += ": " + skipper
+ else:
+ msg = ""
+
+ return msg
+
+
+def make_env_id(tracer):
+ """An environment id that will keep all the test runs distinct."""
+ impl = platform.python_implementation().lower()
+ version = "%s%s" % sys.version_info[:2]
+ if '__pypy__' in sys.builtin_module_names:
+ version += "_%s%s" % sys.pypy_version_info[:2]
+ env_id = "%s%s_%s" % (impl, version, tracer)
+ return env_id
+
+
+def run_tests(tracer, *runner_args):
+ """The actual running of tests."""
+ if 'COVERAGE_TESTING' not in os.environ:
+ os.environ['COVERAGE_TESTING'] = "True"
+ # $set_env.py: COVERAGE_ENV_ID - Use environment-specific test directories.
+ if 'COVERAGE_ENV_ID' in os.environ:
+ os.environ['COVERAGE_ENV_ID'] = make_env_id(tracer)
+ print_banner(label_for_tracer(tracer))
+ return pytest.main(list(runner_args))
+
+
+def run_tests_with_coverage(tracer, *runner_args):
+ """Run tests, but with coverage."""
+ # Need to define this early enough that the first import of env.py sees it.
+ os.environ['COVERAGE_TESTING'] = "True"
+ os.environ['COVERAGE_PROCESS_START'] = os.path.abspath('metacov.ini')
+ os.environ['COVERAGE_HOME'] = os.getcwd()
+
+ # Create the .pth file that will let us measure coverage in sub-processes.
+ # The .pth file seems to have to be alphabetically after easy-install.pth
+ # or the sys.path entries aren't created right?
+ # There's an entry in "make clean" to get rid of this file.
+ pth_dir = os.path.dirname(pytest.__file__)
+ pth_path = os.path.join(pth_dir, "zzz_metacov.pth")
+ with open(pth_path, "w") as pth_file:
+ pth_file.write("import coverage; coverage.process_startup()\n")
+
+ suffix = "%s_%s" % (make_env_id(tracer), platform.platform())
+ os.environ['COVERAGE_METAFILE'] = os.path.abspath(".metacov."+suffix)
+
+ import coverage
+ cov = coverage.Coverage(config_file="metacov.ini")
+ cov._warn_unimported_source = False
+ cov._warn_preimported_source = False
+ cov.start()
+
+ try:
+ # Re-import coverage to get it coverage tested! I don't understand all
+ # the mechanics here, but if I don't carry over the imported modules
+ # (in covmods), then things go haywire (os == None, eventually).
+ covmods = {}
+ covdir = os.path.split(coverage.__file__)[0]
+ # We have to make a list since we'll be deleting in the loop.
+ modules = list(sys.modules.items())
+ for name, mod in modules:
+ if name.startswith('coverage'):
+ if getattr(mod, '__file__', "??").startswith(covdir):
+ covmods[name] = mod
+ del sys.modules[name]
+ import coverage # pylint: disable=reimported
+ sys.modules.update(covmods)
+
+ # Run tests, with the arguments from our command line.
+ status = run_tests(tracer, *runner_args)
+
+ finally:
+ cov.stop()
+ os.remove(pth_path)
+
+ cov.combine()
+ cov.save()
+
+ return status
+
+
+def do_combine_html():
+ """Combine data from a meta-coverage run, and make the HTML and XML reports."""
+ import coverage
+ os.environ['COVERAGE_HOME'] = os.getcwd()
+ os.environ['COVERAGE_METAFILE'] = os.path.abspath(".metacov")
+ cov = coverage.Coverage(config_file="metacov.ini")
+ cov.load()
+ cov.combine()
+ cov.save()
+ show_contexts = bool(os.environ.get('COVERAGE_CONTEXT'))
+ cov.html_report(show_contexts=show_contexts)
+ cov.xml_report()
+
+
+def do_test_with_tracer(tracer, *runner_args):
+ """Run tests with a particular tracer."""
+ # If we should skip these tests, skip them.
+ skip_msg = should_skip(tracer)
+ if skip_msg:
+ print(skip_msg)
+ return None
+
+ os.environ["COVERAGE_TEST_TRACER"] = tracer
+ if os.environ.get("COVERAGE_COVERAGE", "no") == "yes":
+ return run_tests_with_coverage(tracer, *runner_args)
+ else:
+ return run_tests(tracer, *runner_args)
+
+
+def do_zip_mods():
+ """Build the zipmods.zip file."""
+ zf = zipfile.ZipFile("tests/zipmods.zip", "w")
+
+ # Take one file from disk.
+ zf.write("tests/covmodzip1.py", "covmodzip1.py")
+
+ # The others will be various encodings.
+ source = textwrap.dedent(u"""\
+ # coding: {encoding}
+ text = u"{text}"
+ ords = {ords}
+ assert [ord(c) for c in text] == ords
+ print(u"All OK with {encoding}")
+ """)
+ # These encodings should match the list in tests/test_python.py
+ details = [
+ (u'utf8', u'ⓗⓔⓛⓛⓞ, ⓦⓞⓡⓛⓓ'),
+ (u'gb2312', u'你好,世界'),
+ (u'hebrew', u'שלום, עולם'),
+ (u'shift_jis', u'こんにちは世界'),
+ (u'cp1252', u'“hi”'),
+ ]
+ for encoding, text in details:
+ filename = 'encoded_{}.py'.format(encoding)
+ ords = [ord(c) for c in text]
+ source_text = source.format(encoding=encoding, text=text, ords=ords)
+ zf.writestr(filename, source_text.encode(encoding))
+
+ zf.close()
+
+ zf = zipfile.ZipFile("tests/covmain.zip", "w")
+ zf.write("coverage/__main__.py", "__main__.py")
+ zf.close()
+
+
+def do_install_egg():
+ """Install the egg1 egg for tests."""
+ # I am pretty certain there are easier ways to install eggs...
+ cur_dir = os.getcwd()
+ os.chdir("tests/eggsrc")
+ with ignore_warnings():
+ import distutils.core
+ distutils.core.run_setup("setup.py", ["--quiet", "bdist_egg"])
+ egg = glob.glob("dist/*.egg")[0]
+ distutils.core.run_setup(
+ "setup.py", ["--quiet", "easy_install", "--no-deps", "--zip-ok", egg]
+ )
+ os.chdir(cur_dir)
+
+
+def do_check_eol():
+ """Check files for incorrect newlines and trailing whitespace."""
+
+ ignore_dirs = [
+ '.svn', '.hg', '.git',
+ '.tox*',
+ '*.egg-info',
+ '_build',
+ '_spell',
+ ]
+ checked = set()
+
+ def check_file(fname, crlf=True, trail_white=True):
+ """Check a single file for whitespace abuse."""
+ fname = os.path.relpath(fname)
+ if fname in checked:
+ return
+ checked.add(fname)
+
+ line = None
+ with open(fname, "rb") as f:
+ for n, line in enumerate(f, start=1):
+ if crlf:
+ if b"\r" in line:
+ print("%s@%d: CR found" % (fname, n))
+ return
+ if trail_white:
+ line = line[:-1]
+ if not crlf:
+ line = line.rstrip(b'\r')
+ if line.rstrip() != line:
+ print("%s@%d: trailing whitespace found" % (fname, n))
+ return
+
+ if line is not None and not line.strip():
+ print("%s: final blank line" % (fname,))
+
+ def check_files(root, patterns, **kwargs):
+ """Check a number of files for whitespace abuse."""
+ for where, dirs, files in os.walk(root):
+ for f in files:
+ fname = os.path.join(where, f)
+ for p in patterns:
+ if fnmatch.fnmatch(fname, p):
+ check_file(fname, **kwargs)
+ break
+ for ignore_dir in ignore_dirs:
+ ignored = []
+ for dir_name in dirs:
+ if fnmatch.fnmatch(dir_name, ignore_dir):
+ ignored.append(dir_name)
+ for dir_name in ignored:
+ dirs.remove(dir_name)
+
+ check_files("coverage", ["*.py"])
+ check_files("coverage/ctracer", ["*.c", "*.h"])
+ check_files("coverage/htmlfiles", ["*.html", "*.scss", "*.css", "*.js"])
+ check_files("tests", ["*.py"])
+ check_files("tests", ["*,cover"], trail_white=False)
+ check_files("tests/js", ["*.js", "*.html"])
+ check_file("setup.py")
+ check_file("igor.py")
+ check_file("Makefile")
+ check_file(".travis.yml")
+ check_files(".", ["*.rst", "*.txt"])
+ check_files(".", ["*.pip"])
+
+
+def print_banner(label):
+ """Print the version of Python."""
+ try:
+ impl = platform.python_implementation()
+ except AttributeError:
+ impl = "Python"
+
+ version = platform.python_version()
+
+ if '__pypy__' in sys.builtin_module_names:
+ version += " (pypy %s)" % ".".join(str(v) for v in sys.pypy_version_info)
+
+ try:
+ which_python = os.path.relpath(sys.executable)
+ except ValueError:
+ # On Windows having a python executable on a different drive
+ # than the sources cannot be relative.
+ which_python = sys.executable
+ print('=== %s %s %s (%s) ===' % (impl, version, label, which_python))
+ sys.stdout.flush()
+
+
+def do_help():
+ """List the available commands"""
+ items = list(globals().items())
+ items.sort()
+ for name, value in items:
+ if name.startswith('do_'):
+ print("%-20s%s" % (name[3:], value.__doc__))
+
+
+def analyze_args(function):
+ """What kind of args does `function` expect?
+
+ Returns:
+ star, num_pos:
+ star(boolean): Does `function` accept *args?
+ num_args(int): How many positional arguments does `function` have?
+ """
+ try:
+ getargspec = inspect.getfullargspec
+ except AttributeError:
+ getargspec = inspect.getargspec
+ with ignore_warnings():
+ # DeprecationWarning: Use inspect.signature() instead of inspect.getfullargspec()
+ argspec = getargspec(function)
+ return bool(argspec[1]), len(argspec[0])
+
+
+def main(args):
+ """Main command-line execution for igor.
+
+ Verbs are taken from the command line, and extra words taken as directed
+ by the arguments needed by the handler.
+
+ """
+ while args:
+ verb = args.pop(0)
+ handler = globals().get('do_'+verb)
+ if handler is None:
+ print("*** No handler for %r" % verb)
+ return 1
+ star, num_args = analyze_args(handler)
+ if star:
+ # Handler has *args, give it all the rest of the command line.
+ handler_args = args
+ args = []
+ else:
+ # Handler has specific arguments, give it only what it needs.
+ handler_args = args[:num_args]
+ args = args[num_args:]
+ ret = handler(*handler_args)
+ # If a handler returns a failure-like value, stop.
+ if ret:
+ return ret
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))