diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2009-09-22 07:22:56 -0400 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2009-09-22 07:22:56 -0400 |
commit | ff9099051e0daff7b08035713eeca5696ab3217a (patch) | |
tree | 13a391e9010e9e0b99ff403ec2fd0252d460ab5a /coverage | |
parent | e3c0b4b2c7d2a92344d30a25467a1e863bbb7d31 (diff) | |
download | python-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.py | 77 | ||||
-rw-r--r-- | coverage/cmdline.py | 8 | ||||
-rw-r--r-- | coverage/codeunit.py | 5 | ||||
-rw-r--r-- | coverage/control.py | 5 | ||||
-rw-r--r-- | coverage/data.py | 5 | ||||
-rw-r--r-- | coverage/execfile.py | 5 | ||||
-rw-r--r-- | coverage/files.py | 2 | ||||
-rw-r--r-- | coverage/parser.py | 18 | ||||
-rw-r--r-- | coverage/templite.py | 2 |
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] |