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:])) |