1 """Helper for building, testing, and linting coverage.py.
3 To get portability, all these operations are written in Python here instead
4 of in shell scripts, batch files, or Makefiles.
18 # Functions named do_* are executable from the command line: do_blah is run
19 # by "python igor.py blah".
22 def do_remove_extension():
23 """Remove the compiled C extension, no matter what its name."""
31 for pattern
in so_patterns
:
32 pattern
= os
.path
.join("coverage", pattern
)
33 for filename
in glob
.glob(pattern
):
39 def run_tests(tracer
, *nose_args
):
40 """The actual running of tests."""
43 label
= "with Python tracer"
45 label
= "with C tracer"
46 if os
.environ
.get("COVERAGE_NO_EXTENSION"):
47 print("Skipping tests, no C extension in this environment")
50 os
.environ
["COVERAGE_TEST_TRACER"] = tracer
51 nose_args
= ["nosetests"] + list(nose_args
)
52 nose
.core
.main(argv
=nose_args
)
54 def run_tests_with_coverage(tracer
, *nose_args
):
55 """Run tests, but with coverage."""
58 os
.environ
['COVERAGE_PROCESS_START'] = os
.path
.abspath('metacov.ini')
59 os
.environ
['COVERAGE_HOME'] = os
.getcwd()
61 # Create the .pth file that will let us measure coverage in sub-processes.
63 pth_dir
= os
.path
.dirname(os
.path
.dirname(nose
.__file
__))
64 pth_path
= os
.path
.join(pth_dir
, "covcov.pth")
65 pth_file
= open(pth_path
, "w")
67 pth_file
.write("import coverage; coverage.process_startup()\n")
71 version
= "%s%s" % sys
.version_info
[:2]
72 suffix
= "%s_%s_%s" % (version
, tracer
, socket
.gethostname())
74 cov
= coverage
.coverage(config_file
="metacov.ini", data_suffix
=suffix
)
75 # Cheap trick: the coverage code itself is excluded from measurement, but
76 # if we clobber the cover_prefix in the coverage object, we can defeat the
78 cov
.cover_prefix
= "Please measure coverage.py!"
83 # Re-import coverage to get it coverage tested! I don't understand all
84 # the mechanics here, but if I don't carry over the imported modules
85 # (in covmods), then things go haywire (os == None, eventually).
87 covdir
= os
.path
.split(coverage
.__file
__)[0]
88 # We have to make a list since we'll be deleting in the loop.
89 modules
= list(sys
.modules
.items())
90 for name
, mod
in modules
:
91 if name
.startswith('coverage'):
92 if getattr(mod
, '__file__', "??").startswith(covdir
):
95 import coverage
# don't warn about re-import: pylint: disable=W0404
96 sys
.modules
.update(covmods
)
98 # Run nosetests, with the arguments from our command line.
100 run_tests(tracer
, *nose_args
)
102 # nose3 seems to raise SystemExit, not sure why?
110 def do_combine_html():
111 """Combine data from a meta-coverage run, and make the HTML report."""
113 os
.environ
['COVERAGE_HOME'] = os
.getcwd()
114 cov
= coverage
.coverage(config_file
="metacov.ini")
120 def do_test_with_tracer(tracer
, *noseargs
):
121 """Run nosetests with a particular tracer."""
122 if os
.environ
.get("COVERAGE_COVERAGE", ""):
123 return run_tests_with_coverage(tracer
, *noseargs
)
125 return run_tests(tracer
, *noseargs
)
128 """Build the zipmods.zip file."""
129 zf
= zipfile
.ZipFile("tests/zipmods.zip", "w")
130 zf
.write("tests/covmodzip1.py", "covmodzip1.py")
133 def do_install_egg():
134 """Install the egg1 egg for tests."""
135 # I am pretty certain there are easier ways to install eggs...
136 # pylint: disable=F0401,E0611,E1101
137 import distutils
.core
138 cur_dir
= os
.getcwd()
139 os
.chdir("tests/eggsrc")
140 distutils
.core
.run_setup("setup.py", ["--quiet", "bdist_egg"])
141 egg
= glob
.glob("dist/*.egg")[0]
142 distutils
.core
.run_setup(
143 "setup.py", ["--quiet", "easy_install", "--no-deps", "--zip-ok", egg
]
148 """Check files for incorrect newlines and trailing whitespace."""
151 '.svn', '.hg', '.tox', '.tox_kits', 'coverage.egg-info',
152 '_build', 'covtestegg1.egg-info',
156 def check_file(fname
, crlf
=True, trail_white
=True):
157 """Check a single file for whitespace abuse."""
158 fname
= os
.path
.relpath(fname
)
164 for n
, line
in enumerate(open(fname
, "rb")):
167 print("%s@%d: CR found" % (fname
, n
+1))
172 line
= line
.rstrip('\r')
173 if line
.rstrip() != line
:
174 print("%s@%d: trailing whitespace found" % (fname
, n
+1))
177 if line
is not None and not line
.strip():
178 print("%s: final blank line" % (fname
,))
180 def check_files(root
, patterns
, **kwargs
):
181 """Check a number of files for whitespace abuse."""
182 for root
, dirs
, files
in os
.walk(root
):
184 fname
= os
.path
.join(root
, f
)
186 if fnmatch
.fnmatch(fname
, p
):
187 check_file(fname
, **kwargs
)
189 for dir_name
in ignore_dirs
:
191 dirs
.remove(dir_name
)
193 check_files("coverage", ["*.py", "*.c"])
194 check_files("coverage/htmlfiles", ["*.html", "*.css", "*.js"])
195 check_file("tests/farm/html/src/bom.py", crlf
=False)
196 check_files("tests", ["*.py"])
197 check_files("tests", ["*,cover"], trail_white
=False)
198 check_files("tests/js", ["*.js", "*.html"])
199 check_file("setup.py")
200 check_file("igor.py")
201 check_file("Makefile")
202 check_file(".hgignore")
203 check_file(".travis.yml")
204 check_files("doc", ["*.rst"])
205 check_files(".", ["*.txt"])
208 def print_banner(label
):
209 """Print the version of Python."""
211 impl
= platform
.python_implementation()
212 except AttributeError:
215 version
= platform
.python_version()
217 if '__pypy__' in sys
.builtin_module_names
:
218 pypy_version
= sys
.pypy_version_info
# pylint: disable=E1101
219 version
+= " (pypy %s)" % ".".join([str(v
) for v
in pypy_version
])
221 print('=== %s %s %s (%s) ===' % (impl
, version
, label
, sys
.executable
))
225 """List the available commands"""
226 items
= list(globals().items())
228 for name
, value
in items
:
229 if name
.startswith('do_'):
230 print("%-20s%s" % (name
[3:], value
.__doc
__))
234 """Main command-line execution for igor.
236 Verbs are taken from the command line, and extra words taken as directed
237 by the arguments needed by the handler.
242 handler
= globals().get('do_'+verb
)
244 print("*** No handler for %r" % verb
)
246 argspec
= inspect
.getargspec(handler
)
248 # Handler has *args, give it all the rest of the command line.
252 # Handler has specific arguments, give it only what it needs.
253 num_args
= len(argspec
[0])
254 handler_args
= args
[:num_args
]
255 args
= args
[num_args
:]
256 ret
= handler(*handler_args
)
257 # If a handler returns a failure-like value, stop.
261 if __name__
== '__main__':
262 sys
.exit(main(sys
.argv
[1:]))