summaryrefslogtreecommitdiff
path: root/coverage
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2009-09-22 07:22:56 -0400
committerNed Batchelder <ned@nedbatchelder.com>2009-09-22 07:22:56 -0400
commitff9099051e0daff7b08035713eeca5696ab3217a (patch)
tree13a391e9010e9e0b99ff403ec2fd0252d460ab5a /coverage
parente3c0b4b2c7d2a92344d30a25467a1e863bbb7d31 (diff)
downloadpython-coveragepy-git-ff9099051e0daff7b08035713eeca5696ab3217a.tar.gz
The best way to get py3k support: same source runs on both, with some contortions.
Diffstat (limited to 'coverage')
-rw-r--r--coverage/backward.py77
-rw-r--r--coverage/cmdline.py8
-rw-r--r--coverage/codeunit.py5
-rw-r--r--coverage/control.py5
-rw-r--r--coverage/data.py5
-rw-r--r--coverage/execfile.py5
-rw-r--r--coverage/files.py2
-rw-r--r--coverage/parser.py18
-rw-r--r--coverage/templite.py2
9 files changed, 67 insertions, 60 deletions
diff --git a/coverage/backward.py b/coverage/backward.py
index 94abdd8c..d21e6a87 100644
--- a/coverage/backward.py
+++ b/coverage/backward.py
@@ -1,8 +1,10 @@
"""Add things to old Pythons so I can pretend they are newer."""
-# pylint: disable-msg=W0622
-# (Redefining built-in blah)
-# The whole point of this file is to redefine built-ins, so shut up about it.
+# This file does lots of tricky stuff, so disable a bunch of lintisms.
+# pylint: disable-msg=F0401,W0611,W0622
+# F0401: Unable to import blah
+# W0611: Unused import blah
+# W0622: Redefining built-in blah
import os, sys
@@ -23,41 +25,40 @@ except NameError:
lst.sort()
return lst
-# Py2k and 3k don't agree on how to run commands in a subprocess.
+# Pythons 2 and 3 differ on where to get StringIO
+
try:
- import subprocess
+ from cStringIO import StringIO
except ImportError:
- def run_command(cmd):
- """Run a command in a subprocess.
-
- Returns the exit code and the combined stdout and stderr.
-
- """
- _, stdouterr = os.popen4(cmd)
- return 0, stdouterr.read()
+ from io import StringIO
+
+# What's a string called?
+
+try:
+ string_class = basestring
+except NameError:
+ string_class = str
+
+# Where do pickles come from?
+
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
+
+# Exec is a statement in Py2, a function in Py3
+
+if sys.hexversion > 0x03000000:
+ def exec_function(source, filename, global_map):
+ """A wrapper around exec()."""
+ exec(compile(source, filename, "exec"), global_map)
else:
- def run_command(cmd):
- """Run a command in a subprocess.
-
- Returns the exit code and the combined stdout and stderr.
-
- """
-
- if sys.hexversion > 0x03000000 and cmd.startswith("coverage "):
- # We don't have a coverage command on 3.x, so fix it up to call the
- # script. Eventually we won't need this.
- cmd = "python " + sys.prefix + os.sep + "Scripts" + os.sep + cmd
-
- proc = subprocess.Popen(cmd, shell=True,
- stdin=subprocess.PIPE, stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT
- )
- retcode = proc.wait()
-
- # Get the output, and canonicalize it to strings with newlines.
- output = proc.stdout.read()
- if not isinstance(output, str):
- output = output.decode('utf-8')
- output = output.replace('\r', '')
-
- return retcode, output
+ # OK, this is pretty gross. In Py2, exec was a statement, but that will
+ # be a syntax error if we try to put it in a Py3 file, even if it is never
+ # executed. So hide it inside an evaluated string literal instead.
+ eval(compile("""\
+def exec_function(source, filename, global_map):
+ exec compile(source, filename, "exec") in global_map
+""",
+ "<exec_function>", "exec"
+ ))
diff --git a/coverage/cmdline.py b/coverage/cmdline.py
index 1348a743..587fac51 100644
--- a/coverage/cmdline.py
+++ b/coverage/cmdline.py
@@ -279,17 +279,17 @@ class CoverageScript:
"""Display an error message, or the named topic."""
assert error or topic or parser
if error:
- print error
- print "Use 'coverage help' for help."
+ print(error)
+ print("Use 'coverage help' for help.")
elif parser:
- print parser.format_help(),
+ print(parser.format_help().strip())
else:
# Parse out the topic we want from HELP_TOPICS
import re
topic_list = re.split("(?m)^=+ (\w+) =+$", HELP_TOPICS)
topics = dict(zip(topic_list[1::2], topic_list[2::2]))
help_msg = topics[topic].strip()
- print help_msg % self.covpkg.__dict__
+ print(help_msg % self.covpkg.__dict__)
def command_line(self, argv):
"""The bulk of the command line interface to Coverage.
diff --git a/coverage/codeunit.py b/coverage/codeunit.py
index 7f4ed966..53c98fc7 100644
--- a/coverage/codeunit.py
+++ b/coverage/codeunit.py
@@ -2,6 +2,9 @@
import glob, os
+from coverage.backward import string_class
+
+
def code_unit_factory(morfs, file_locator, omit_prefixes=None):
"""Construct a list of CodeUnits from polymorphic inputs.
@@ -21,7 +24,7 @@ def code_unit_factory(morfs, file_locator, omit_prefixes=None):
# On Windows, the shell doesn't expand wildcards. Do it here.
globbed = []
for morf in morfs:
- if isinstance(morf, basestring) and ('?' in morf or '*' in morf):
+ if isinstance(morf, string_class) and ('?' in morf or '*' in morf):
globbed.extend(glob.glob(morf))
else:
globbed.append(morf)
diff --git a/coverage/control.py b/coverage/control.py
index 19675cf6..4cf97d40 100644
--- a/coverage/control.py
+++ b/coverage/control.py
@@ -3,6 +3,7 @@
import os, socket
from coverage.annotate import AnnotateReporter
+from coverage.backward import string_class
from coverage.codeunit import code_unit_factory
from coverage.collector import Collector
from coverage.data import CoverageData
@@ -68,7 +69,7 @@ class coverage:
# Create the data file.
if data_suffix:
- if not isinstance(data_suffix, basestring):
+ if not isinstance(data_suffix, string_class):
# if data_suffix=True, use .machinename.pid
data_suffix = ".%s.%s" % (socket.gethostname(), os.getpid())
else:
@@ -136,7 +137,7 @@ class coverage:
def _should_trace(self, filename, frame): # pylint: disable-msg=E0102
"""A logging decorator around the real _should_trace function."""
ret = self._real_should_trace(filename, frame)
- print "should_trace: %r -> %r" % (filename, ret)
+ print("should_trace: %r -> %r" % (filename, ret))
return ret
def use_cache(self, usecache):
diff --git a/coverage/data.py b/coverage/data.py
index 2fb635ee..4d368f55 100644
--- a/coverage/data.py
+++ b/coverage/data.py
@@ -1,9 +1,8 @@
"""Coverage data for Coverage."""
import os
-import cPickle as pickle
-from coverage.backward import sorted # pylint: disable-msg=W0622
+from coverage.backward import pickle, sorted # pylint: disable-msg=W0622
class CoverageData:
@@ -154,7 +153,7 @@ class CoverageData:
def executed_files(self):
"""A list of all files that had been measured as executed."""
- return self.lines.keys()
+ return list(self.lines.keys())
def executed_lines(self, filename):
"""A map containing all the line numbers executed in `filename`.
diff --git a/coverage/execfile.py b/coverage/execfile.py
index a345c767..cf8e1ec2 100644
--- a/coverage/execfile.py
+++ b/coverage/execfile.py
@@ -2,6 +2,9 @@
import imp, os, sys
+from coverage.backward import exec_function
+
+
try:
# In Py 2.x, the builtins were in __builtin__
BUILTINS = sys.modules['__builtin__']
@@ -33,7 +36,7 @@ def run_python_file(filename, args):
try:
source = open(filename, 'rU').read()
- exec compile(source, filename, "exec") in main_mod.__dict__
+ exec_function(source, filename, main_mod.__dict__)
finally:
# Restore the old __main__
sys.modules['__main__'] = old_main_mod
diff --git a/coverage/files.py b/coverage/files.py
index f3fafdfb..c16f113d 100644
--- a/coverage/files.py
+++ b/coverage/files.py
@@ -31,7 +31,7 @@ class FileLocator:
An absolute path with no redundant components and normalized case.
"""
- if not self.canonical_filename_cache.has_key(filename):
+ if filename not in self.canonical_filename_cache:
f = filename
if os.path.isabs(f) and not os.path.exists(f):
if not self.get_zip_data(f):
diff --git a/coverage/parser.py b/coverage/parser.py
index 4ec9c3c5..75910428 100644
--- a/coverage/parser.py
+++ b/coverage/parser.py
@@ -1,10 +1,9 @@
"""Code parsing for Coverage."""
import re, sys, token, tokenize, types
-import cStringIO as StringIO
from coverage.misc import nice_pair, CoverageException
-from coverage.backward import set # pylint: disable-msg=W0622
+from coverage.backward import set, StringIO # pylint: disable-msg=W0622
@@ -107,13 +106,13 @@ class CodeParser:
prev_toktype = token.INDENT
first_line = None
- tokgen = tokenize.generate_tokens(StringIO.StringIO(text).readline)
+ tokgen = tokenize.generate_tokens(StringIO(text).readline)
for toktype, ttext, (slineno, _), (elineno, _), ltext in tokgen:
if self.show_tokens:
- print "%10s %5s %-20r %r" % (
+ print("%10s %5s %-20r %r" % (
tokenize.tok_name.get(toktype, toktype),
nice_pair((slineno, elineno)), ttext, ltext
- )
+ ))
if toktype == token.INDENT:
indent += 1
elif toktype == token.DEDENT:
@@ -128,7 +127,7 @@ class CodeParser:
elif toktype == token.STRING and prev_toktype == token.INDENT:
# Strings that are first on an indented line are docstrings.
# (a trick from trace.py in the stdlib.)
- for i in xrange(slineno, elineno+1):
+ for i in range(slineno, elineno+1):
self.docstrings.add(i)
elif toktype == token.NEWLINE:
if first_line is not None and elineno != first_line:
@@ -136,7 +135,7 @@ class CodeParser:
# different line than the first line of the statement,
# so record a multi-line range.
rng = (first_line, elineno)
- for l in xrange(first_line, elineno+1):
+ for l in range(first_line, elineno+1):
self.multiline[l] = rng
first_line = None
@@ -161,7 +160,8 @@ class CodeParser:
# text ends nicely for them.
text += '\n'
code = compile(text, filename, "exec")
- except SyntaxError, synerr:
+ except SyntaxError:
+ _, synerr, _ = sys.exc_info()
raise CoverageException(
"Couldn't parse '%s' as Python source: '%s' at line %d" %
(filename, synerr.msg, synerr.lineno)
@@ -225,7 +225,7 @@ class CodeParser:
m1 = '"'
if lineno in self.excluded:
m2 = 'x'
- print "%4d %s%s%s %s" % (lineno, m0, m1, m2, ltext)
+ print("%4d %s%s%s %s" % (lineno, m0, m1, m2, ltext))
if __name__ == '__main__':
diff --git a/coverage/templite.py b/coverage/templite.py
index 75fce6d6..23c805b1 100644
--- a/coverage/templite.py
+++ b/coverage/templite.py
@@ -106,7 +106,7 @@ class _ContextAccess(object):
value = getattr(value, dot)
except AttributeError:
value = value[dot]
- if callable(value):
+ if hasattr(value, '__call__'):
value = value()
else:
value = self.context[key]