| Index: tools/telemetry/third_party/coverage/igor.py
|
| diff --git a/third_party/pycoverage/igor.py b/tools/telemetry/third_party/coverage/igor.py
|
| similarity index 51%
|
| copy from third_party/pycoverage/igor.py
|
| copy to tools/telemetry/third_party/coverage/igor.py
|
| index 12ec6c8fec4afe1fe482cbcbcda18759135ff60e..8e172db0211477b0ae9e16d8108b431e1236e44d 100644
|
| --- a/third_party/pycoverage/igor.py
|
| +++ b/tools/telemetry/third_party/coverage/igor.py
|
| @@ -1,3 +1,7 @@
|
| +# coding: utf-8
|
| +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
|
| +# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
|
| +
|
| """Helper for building, testing, and linting coverage.py.
|
|
|
| To get portability, all these operations are written in Python here instead
|
| @@ -5,20 +9,42 @@ of in shell scripts, batch files, or Makefiles.
|
|
|
| """
|
|
|
| +import contextlib
|
| import fnmatch
|
| import glob
|
| import inspect
|
| import os
|
| import platform
|
| -import socket
|
| import sys
|
| +import textwrap
|
| +import warnings
|
| import zipfile
|
|
|
|
|
| +# We want to see all warnings while we are running tests. But we also need to
|
| +# disable warnings for some of the more complex setting up of tests.
|
| +warnings.simplefilter("default")
|
| +
|
| +
|
| +@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."""
|
|
|
| @@ -26,6 +52,7 @@ def do_remove_extension():
|
| tracer.so
|
| tracer.*.so
|
| tracer.pyd
|
| + tracer.*.pyd
|
| """.split()
|
|
|
| for pattern in so_patterns:
|
| @@ -36,47 +63,82 @@ def do_remove_extension():
|
| except OSError:
|
| pass
|
|
|
| -def run_tests(tracer, *nose_args):
|
| - """The actual running of tests."""
|
| - import nose.core
|
| +
|
| +def label_for_tracer(tracer):
|
| + """Get the label for these tests."""
|
| if tracer == "py":
|
| label = "with Python tracer"
|
| else:
|
| label = "with C tracer"
|
| - if os.environ.get("COVERAGE_NO_EXTENSION"):
|
| - print("Skipping tests, no C extension in this environment")
|
| - return
|
| - print_banner(label)
|
| - os.environ["COVERAGE_TEST_TRACER"] = tracer
|
| +
|
| + return label
|
| +
|
| +
|
| +def should_skip(tracer):
|
| + """Is there a reason to skip these tests?"""
|
| + if tracer == "py":
|
| + skipper = os.environ.get("COVERAGE_NO_PYTRACER")
|
| + else:
|
| + skipper = (
|
| + os.environ.get("COVERAGE_NO_EXTENSION") or
|
| + 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 run_tests(tracer, *nose_args):
|
| + """The actual running of tests."""
|
| + with ignore_warnings():
|
| + import nose.core
|
| +
|
| + if 'COVERAGE_TESTING' not in os.environ:
|
| + os.environ['COVERAGE_TESTING'] = "True"
|
| + print_banner(label_for_tracer(tracer))
|
| nose_args = ["nosetests"] + list(nose_args)
|
| nose.core.main(argv=nose_args)
|
|
|
| +
|
| def run_tests_with_coverage(tracer, *nose_args):
|
| """Run tests, but with coverage."""
|
| - import 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?
|
| import nose
|
| pth_dir = os.path.dirname(os.path.dirname(nose.__file__))
|
| - pth_path = os.path.join(pth_dir, "covcov.pth")
|
| - pth_file = open(pth_path, "w")
|
| - try:
|
| + 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")
|
| - finally:
|
| - pth_file.close()
|
|
|
| + # Make names for the data files that keep all the test runs distinct.
|
| + impl = platform.python_implementation().lower()
|
| version = "%s%s" % sys.version_info[:2]
|
| - suffix = "%s_%s_%s" % (version, tracer, socket.gethostname())
|
| + if '__pypy__' in sys.builtin_module_names:
|
| + version += "_%s%s" % sys.pypy_version_info[:2]
|
| + suffix = "%s%s_%s_%s" % (impl, version, tracer, platform.platform())
|
| +
|
| + os.environ['COVERAGE_METAFILE'] = os.path.abspath(".metacov."+suffix)
|
|
|
| - cov = coverage.coverage(config_file="metacov.ini", data_suffix=suffix)
|
| - # Cheap trick: the coverage code itself is excluded from measurement, but
|
| - # if we clobber the cover_prefix in the coverage object, we can defeat the
|
| - # self-detection.
|
| + import coverage
|
| + cov = coverage.Coverage(config_file="metacov.ini", data_suffix=False)
|
| + # Cheap trick: the coverage.py code itself is excluded from measurement,
|
| + # but if we clobber the cover_prefix in the coverage object, we can defeat
|
| + # the self-detection.
|
| cov.cover_prefix = "Please measure coverage.py!"
|
| - cov.erase()
|
| + cov._warn_unimported_source = False
|
| cov.start()
|
|
|
| try:
|
| @@ -92,7 +154,7 @@ def run_tests_with_coverage(tracer, *nose_args):
|
| if getattr(mod, '__file__', "??").startswith(covdir):
|
| covmods[name] = mod
|
| del sys.modules[name]
|
| - import coverage # don't warn about re-import: pylint: disable=W0404
|
| + import coverage # pylint: disable=reimported
|
| sys.modules.update(covmods)
|
|
|
| # Run nosetests, with the arguments from our command line.
|
| @@ -105,53 +167,94 @@ def run_tests_with_coverage(tracer, *nose_args):
|
| cov.stop()
|
| os.remove(pth_path)
|
|
|
| + cov.combine()
|
| cov.save()
|
|
|
| +
|
| def do_combine_html():
|
| - """Combine data from a meta-coverage run, and make the HTML report."""
|
| + """Combine data from a meta-coverage run, and make the HTML and XML reports."""
|
| import coverage
|
| os.environ['COVERAGE_HOME'] = os.getcwd()
|
| - cov = coverage.coverage(config_file="metacov.ini")
|
| + os.environ['COVERAGE_METAFILE'] = os.path.abspath(".metacov")
|
| + cov = coverage.Coverage(config_file="metacov.ini")
|
| cov.load()
|
| cov.combine()
|
| cov.save()
|
| cov.html_report()
|
| + cov.xml_report()
|
| +
|
|
|
| def do_test_with_tracer(tracer, *noseargs):
|
| """Run nosetests with a particular tracer."""
|
| + # If we should skip these tests, skip them.
|
| + skip_msg = should_skip(tracer)
|
| + if skip_msg:
|
| + print(skip_msg)
|
| + return
|
| +
|
| + os.environ["COVERAGE_TEST_TRACER"] = tracer
|
| if os.environ.get("COVERAGE_COVERAGE", ""):
|
| return run_tests_with_coverage(tracer, *noseargs)
|
| else:
|
| return run_tests(tracer, *noseargs)
|
|
|
| +
|
| 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}")
|
| + """)
|
| + details = [
|
| + (u'utf8', u'ⓗⓔⓛⓛⓞ, ⓦⓞⓡⓛⓓ'),
|
| + (u'gb2312', u'你好,世界'),
|
| + (u'hebrew', u'שלום, עולם'),
|
| + (u'shift_jis', u'こんにちは世界'),
|
| + ]
|
| + for encoding, text in details:
|
| + filename = 'encoded_{0}.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()
|
|
|
| +
|
| def do_install_egg():
|
| """Install the egg1 egg for tests."""
|
| # I am pretty certain there are easier ways to install eggs...
|
| - # pylint: disable=F0401,E0611,E1101
|
| - import distutils.core
|
| + # pylint: disable=import-error,no-name-in-module
|
| cur_dir = os.getcwd()
|
| os.chdir("tests/eggsrc")
|
| - 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]
|
| - )
|
| + 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', '.tox', '.tox_kits', 'coverage.egg-info',
|
| - '_build', 'covtestegg1.egg-info',
|
| + '.svn', '.hg', '.git',
|
| + '.tox*',
|
| + '*.egg-info',
|
| + '_build',
|
| ]
|
| - checked = set([])
|
| + checked = set()
|
|
|
| def check_file(fname, crlf=True, trail_white=True):
|
| """Check a single file for whitespace abuse."""
|
| @@ -161,18 +264,19 @@ def do_check_eol():
|
| checked.add(fname)
|
|
|
| line = None
|
| - for n, line in enumerate(open(fname, "rb")):
|
| - if crlf:
|
| - if "\r" in line:
|
| - print("%s@%d: CR found" % (fname, n+1))
|
| - return
|
| - if trail_white:
|
| - line = line[:-1]
|
| - if not crlf:
|
| - line = line.rstrip('\r')
|
| - if line.rstrip() != line:
|
| - print("%s@%d: trailing whitespace found" % (fname, n+1))
|
| - return
|
| + with open(fname, "rb") as f:
|
| + for n, line in enumerate(f, start=1):
|
| + if crlf:
|
| + if "\r" in line:
|
| + print("%s@%d: CR found" % (fname, n))
|
| + return
|
| + if trail_white:
|
| + line = line[:-1]
|
| + if not crlf:
|
| + line = line.rstrip('\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,))
|
| @@ -186,11 +290,16 @@ def do_check_eol():
|
| if fnmatch.fnmatch(fname, p):
|
| check_file(fname, **kwargs)
|
| break
|
| - for dir_name in ignore_dirs:
|
| - if dir_name in dirs:
|
| + 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", "*.c"])
|
| + check_files("coverage", ["*.py"])
|
| + check_files("coverage/ctracer", ["*.c", "*.h"])
|
| check_files("coverage/htmlfiles", ["*.html", "*.css", "*.js"])
|
| check_file("tests/farm/html/src/bom.py", crlf=False)
|
| check_files("tests", ["*.py"])
|
| @@ -201,8 +310,8 @@ def do_check_eol():
|
| check_file("Makefile")
|
| check_file(".hgignore")
|
| check_file(".travis.yml")
|
| - check_files("doc", ["*.rst"])
|
| - check_files(".", ["*.txt"])
|
| + check_files(".", ["*.rst", "*.txt"])
|
| + check_files(".", ["*.pip"])
|
|
|
|
|
| def print_banner(label):
|
| @@ -215,10 +324,11 @@ def print_banner(label):
|
| version = platform.python_version()
|
|
|
| if '__pypy__' in sys.builtin_module_names:
|
| - pypy_version = sys.pypy_version_info # pylint: disable=E1101
|
| - version += " (pypy %s)" % ".".join([str(v) for v in pypy_version])
|
| + version += " (pypy %s)" % ".".join(str(v) for v in sys.pypy_version_info)
|
|
|
| - print('=== %s %s %s (%s) ===' % (impl, version, label, sys.executable))
|
| + which_python = os.path.relpath(sys.executable)
|
| + print('=== %s %s %s (%s) ===' % (impl, version, label, which_python))
|
| + sys.stdout.flush()
|
|
|
|
|
| def do_help():
|
| @@ -230,6 +340,22 @@ def do_help():
|
| 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
|
| + argspec = getargspec(function)
|
| + return bool(argspec[1]), len(argspec[0])
|
| +
|
| +
|
| def main(args):
|
| """Main command-line execution for igor.
|
|
|
| @@ -243,14 +369,13 @@ def main(args):
|
| if handler is None:
|
| print("*** No handler for %r" % verb)
|
| return 1
|
| - argspec = inspect.getargspec(handler)
|
| - if argspec[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.
|
| - num_args = len(argspec[0])
|
| handler_args = args[:num_args]
|
| args = args[num_args:]
|
| ret = handler(*handler_args)
|
| @@ -258,5 +383,6 @@ def main(args):
|
| if ret:
|
| return ret
|
|
|
| +
|
| if __name__ == '__main__':
|
| sys.exit(main(sys.argv[1:]))
|
|
|