Ned Batchelder avatar Ned Batchelder committed 0462e94 Merge

Merged 4.0 to default

Comments (0)

Files changed (43)

 Change history for Coverage.py
 ------------------------------
 
+4.0
+---
+
+- Python versions supported are now 2.6, 2.7, 3.2, 3.3.
+
+
 3.7.1 -- 13 December 2013
 -------------------------
 
     - --branch = True ?
 
 - Remove 2.3, 2.4, 2.5 limitations
-    - set, sorted, reversed, rpartition
-    - generator expressions
-    - decorators
-    - collections.defaultdict
-    - .startswith((,))
+    + set, sorted, reversed, rpartition
+    + generator expressions
+    + decorators
+    + collections.defaultdict
+    + .startswith((,))
+    + "with" statements
+    - .format() ?
+    + try/except/finally
     - with assertRaises
     - exec statement can look like a function in py2 (since when?)
 
-- Remove code only run on <2.6
++ Remove code only run on <2.6
 - Change data file to json
 - Create data api
 - New ast-based branch coverage?

coverage/annotate.py

 
 import os, re
 
-from coverage.backward import sorted                    # pylint: disable=W0622
 from coverage.report import Reporter
 
 class AnnotateReporter(Reporter):

coverage/backward.py

 
 import os, re, sys
 
-# Python 2.3 doesn't have `set`
-try:
-    set = set       # new in 2.4
-except NameError:
-    from sets import Set as set
-
-# Python 2.3 doesn't have `sorted`.
-try:
-    sorted = sorted
-except NameError:
-    def sorted(iterable):
-        """A 2.3-compatible implementation of `sorted`."""
-        lst = list(iterable)
-        lst.sort()
-        return lst
-
-# Python 2.3 doesn't have `reversed`.
-try:
-    reversed = reversed
-except NameError:
-    def reversed(iterable):
-        """A 2.3-compatible implementation of `reversed`."""
-        lst = list(iterable)
-        return lst[::-1]
-
-# rpartition is new in 2.5
-try:
-    "".rpartition
-except AttributeError:
-    def rpartition(s, sep):
-        """Implement s.rpartition(sep) for old Pythons."""
-        i = s.rfind(sep)
-        if i == -1:
-            return ('', '', s)
-        else:
-            return (s[:i], sep, s[i+len(sep):])
-else:
-    def rpartition(s, sep):
-        """A common interface for new Pythons."""
-        return s.rpartition(sep)
-
 # Pythons 2 and 3 differ on where to get StringIO
 try:
     from cStringIO import StringIO
 
     def binary_bytes(byte_values):
         """Produce a byte string with the ints from `byte_values`."""
-        return "".join([chr(b) for b in byte_values])
+        return "".join(chr(b) for b in byte_values)
 
     def byte_to_int(byte_value):
         """Turn an element of a bytes object into an int."""

coverage/cmdline.py

 
 import optparse, os, sys, time, traceback
 
-from coverage.backward import sorted                # pylint: disable=W0622
 from coverage.execfile import run_python_file, run_python_module
 from coverage.misc import CoverageException, ExceptionDuringRun, NoSource
 from coverage.debug import info_formatter
         self.coverage.start()
         code_ran = True
         try:
-            try:
-                if options.module:
-                    sys.path[0] = ''
-                    self.run_python_module(args[0], args)
-                else:
-                    filename = args[0]
-                    sys.path[0] = os.path.abspath(os.path.dirname(filename))
-                    self.run_python_file(filename, args)
-            except NoSource:
-                code_ran = False
-                raise
+            if options.module:
+                sys.path[0] = ''
+                self.run_python_module(args[0], args)
+            else:
+                filename = args[0]
+                sys.path[0] = os.path.abspath(os.path.dirname(filename))
+                self.run_python_file(filename, args)
+        except NoSource:
+            code_ran = False
+            raise
         finally:
             self.coverage.stop()
             if code_ran:
         end = time.clock()
         if 0:
             print("time: %.3fs" % (end - start))
-    except ExceptionDuringRun:
+    except ExceptionDuringRun as err:
         # An exception was caught while running the product code.  The
         # sys.exc_info() return tuple is packed into an ExceptionDuringRun
         # exception.
-        _, err, _ = sys.exc_info()
         traceback.print_exception(*err.args)
         status = ERR
-    except CoverageException:
+    except CoverageException as err:
         # A controlled error inside coverage.py: print the message to the user.
-        _, err, _ = sys.exc_info()
         print(err)
         status = ERR
-    except SystemExit:
+    except SystemExit as err:
         # The user called `sys.exit()`.  Exit with their argument, if any.
-        _, err, _ = sys.exc_info()
         if err.args:
             status = err.args[0]
         else:

coverage/codeunit.py

         else:
             f = morf
         # .pyc files should always refer to a .py instead.
-        if f.endswith('.pyc') or f.endswith('.pyo'):
+        if f.endswith(('.pyc', '.pyo')):
             f = f[:-1]
         elif f.endswith('$py.class'): # Jython
             f = f[:-9] + ".py"

coverage/config.py

         def dollar_replace(m):
             """Called for each $replacement."""
             # Only one of the groups will have matched, just get its text.
-            word = [w for w in m.groups() if w is not None][0]
+            word = next(w for w in m.groups() if w is not None)
             if word == "$":
                 return "$"
             else:

coverage/control.py

 import atexit, os, random, socket, sys
 
 from coverage.annotate import AnnotateReporter
-from coverage.backward import string_class, iitems, sorted  # pylint: disable=W0622
+from coverage.backward import string_class, iitems
 from coverage.codeunit import code_unit_factory, CodeUnit
 from coverage.collector import Collector
 from coverage.config import CoverageConfig
                 config_file = ".coveragerc"
             try:
                 self.config.from_file(config_file)
-            except ValueError:
-                _, err, _ = sys.exc_info()
+            except ValueError as err:
                 raise CoverageException(
                     "Couldn't read config file %s: %s" % (config_file, err)
                     )
                 outfile = open(self.config.xml_output, "w")
                 file_to_close = outfile
         try:
-            try:
-                reporter = XmlReporter(self, self.config)
-                return reporter.report(morfs, outfile=outfile)
-            except CoverageException:
-                delete_file = True
-                raise
+            reporter = XmlReporter(self, self.config)
+            return reporter.report(morfs, outfile=outfile)
+        except CoverageException:
+            delete_file = True
+            raise
         finally:
             if file_to_close:
                 file_to_close.close()
 
 import os
 
-from coverage.backward import iitems, pickle, sorted    # pylint: disable=W0622
+from coverage.backward import iitems, pickle
 from coverage.files import PathAliases
 from coverage.misc import file_be_gone
 
     def line_data(self):
         """Return the map from filenames to lists of line numbers executed."""
         return dict(
-            [(f, sorted(lmap.keys())) for f, lmap in iitems(self.lines)]
+            (f, sorted(lmap.keys())) for f, lmap in iitems(self.lines)
             )
 
     def arc_data(self):
         """Return the map from filenames to lists of line number pairs."""
         return dict(
-            [(f, sorted(amap.keys())) for f, amap in iitems(self.arcs)]
+            (f, sorted(amap.keys())) for f, amap in iitems(self.arcs)
             )
 
     def write_file(self, filename):
             self.debug.write("Writing data to %r" % (filename,))
 
         # Write the pickle to the file.
-        fdata = open(filename, 'wb')
-        try:
+        with open(filename, 'wb') as fdata:
             pickle.dump(data, fdata, 2)
-        finally:
-            fdata.close()
 
     def read_file(self, filename):
         """Read the coverage data from `filename`."""
         """Return the raw pickled data from `filename`."""
         if self.debug and self.debug.should('dataio'):
             self.debug.write("Reading data from %r" % (filename,))
-        fdata = open(filename, 'rb')
-        try:
+        with open(filename, 'rb') as fdata:
             data = pickle.load(fdata)
-        finally:
-            fdata.close()
         return data
 
     def _read_file(self, filename):

coverage/debug.py

     nicely formatted, ready to print.
 
     """
-    label_len = max([len(l) for l, _d in info])
+    label_len = max(len(l) for l, _d in info)
     for label, data in info:
         if data == []:
             data = "-none-"

coverage/execfile.py

     openfile = None
     glo, loc = globals(), locals()
     try:
-        try:
-            # Search for the module - inside its parent package, if any - using
-            # standard import mechanics.
-            if '.' in modulename:
-                packagename, name = rsplit1(modulename, '.')
-                package = __import__(packagename, glo, loc, ['__path__'])
-                searchpath = package.__path__
-            else:
-                packagename, name = None, modulename
-                searchpath = None  # "top-level search" in imp.find_module()
+        # Search for the module - inside its parent package, if any - using
+        # standard import mechanics.
+        if '.' in modulename:
+            packagename, name = rsplit1(modulename, '.')
+            package = __import__(packagename, glo, loc, ['__path__'])
+            searchpath = package.__path__
+        else:
+            packagename, name = None, modulename
+            searchpath = None  # "top-level search" in imp.find_module()
+        openfile, pathname, _ = imp.find_module(name, searchpath)
+
+        # Complain if this is a magic non-file module.
+        if openfile is None and pathname is None:
+            raise NoSource(
+                "module does not live in a file: %r" % modulename
+                )
+
+        # If `modulename` is actually a package, not a mere module, then we
+        # pretend to be Python 2.7 and try running its __main__.py script.
+        if openfile is None:
+            packagename = modulename
+            name = '__main__'
+            package = __import__(packagename, glo, loc, ['__path__'])
+            searchpath = package.__path__
             openfile, pathname, _ = imp.find_module(name, searchpath)
-
-            # Complain if this is a magic non-file module.
-            if openfile is None and pathname is None:
-                raise NoSource(
-                    "module does not live in a file: %r" % modulename
-                    )
-
-            # If `modulename` is actually a package, not a mere module, then we
-            # pretend to be Python 2.7 and try running its __main__.py script.
-            if openfile is None:
-                packagename = modulename
-                name = '__main__'
-                package = __import__(packagename, glo, loc, ['__path__'])
-                searchpath = package.__path__
-                openfile, pathname, _ = imp.find_module(name, searchpath)
-        except ImportError:
-            _, err, _ = sys.exc_info()
-            raise NoSource(str(err))
+    except ImportError as err:
+        raise NoSource(str(err))
     finally:
         if openfile:
             openfile.close()
 
     try:
         # Make a code object somehow.
-        if filename.endswith(".pyc") or filename.endswith(".pyo"):
+        if filename.endswith((".pyc", ".pyo")):
             code = make_code_from_pyc(filename)
         else:
             code = make_code_from_py(filename)
     except IOError:
         raise NoSource("No file to run: %r" % filename)
 
-    try:
+    with source_file:
         source = source_file.read()
-    finally:
-        source_file.close()
 
     # We have the source.  `compile` still needs the last line to be clean,
     # so make sure it is, then compile a code object from it.
     except IOError:
         raise NoCode("No file to run: %r" % filename)
 
-    try:
+    with fpyc:
         # First four bytes are a version-specific magic number.  It has to
         # match or we won't run the file.
         magic = fpyc.read(4)
 
         # The rest of the file is the code object we want.
         code = marshal.load(fpyc)
-    finally:
-        fpyc.close()
 
     return code

coverage/files.py

     """
     prepped = []
     for p in patterns or []:
-        if p.startswith("*") or p.startswith("?"):
+        if p.startswith(("*", "?")):
             prepped.append(p)
         else:
             prepped.append(abs_file(p))
 
 def data(fname):
     """Return the contents of a data file of ours."""
-    data_file = open(data_filename(fname))
-    try:
+    with open(data_filename(fname)) as data_file:
         return data_file.read()
-    finally:
-        data_file.close()
 
 
 class HtmlReporter(Reporter):
 
     def write_html(self, fname, html):
         """Write `html` to `fname`, properly encoded."""
-        fout = open(fname, "wb")
-        try:
+        with open(fname, "wb") as fout:
             fout.write(html.encode('ascii', 'xmlcharrefreplace'))
-        finally:
-            fout.close()
 
     def file_hash(self, source, cu):
         """Compute a hash that changes if the file needs to be re-reported."""
     def html_file(self, cu, analysis):
         """Generate an HTML file for one source file."""
         source_file = cu.source_file()
-        try:
+        with source_file:
             source = source_file.read()
-        finally:
-            source_file.close()
 
         # Find out if the file on disk is already correct.
         flat_rootname = cu.flat_rootname()
 
         lines = []
 
-        for lineno, line in enumerate(source_token_lines(source)):
-            lineno += 1     # 1-based line numbers.
+        for lineno, line in enumerate(source_token_lines(source), start=1):
             # Figure out how to mark this line.
             line_class = []
             annotate_html = ""
             data("index.html"), self.template_globals
             )
 
-        self.totals = sum([f['nums'] for f in self.files])
+        self.totals = sum(f['nums'] for f in self.files)
 
         html = index_tmpl.render({
             'arcs': self.arcs,
         usable = False
         try:
             status_file = os.path.join(directory, self.STATUS_FILE)
-            fstatus = open(status_file, "rb")
-            try:
+            with open(status_file, "rb") as fstatus:
                 status = pickle.load(fstatus)
-            finally:
-                fstatus.close()
         except (IOError, ValueError):
             usable = False
         else:
             'settings': self.settings,
             'files': self.files,
             }
-        fout = open(status_file, "wb")
-        try:
+        with open(status_file, "wb") as fout:
             pickle.dump(status, fout)
-        finally:
-            fout.close()
 
     def settings_hash(self):
         """Get the hash of the coverage.py settings."""
 import errno
 import inspect
 import os
-import sys
 
-from coverage.backward import md5, sorted       # pylint: disable=W0622
+from coverage.backward import md5
 from coverage.backward import string_class, to_bytes
 
 
 def short_stack():
     """Return a string summarizing the call stack."""
     stack = inspect.stack()[:0:-1]
-    return "\n".join(["%30s : %s @%d" % (t[3],t[1],t[2]) for t in stack])
+    return "\n".join("%30s : %s @%d" % (t[3],t[1],t[2]) for t in stack)
 
 
 def expensive(fn):
 def join_regex(regexes):
     """Combine a list of regexes into one that matches any of them."""
     if len(regexes) > 1:
-        return "|".join(["(%s)" % r for r in regexes])
+        return "|".join("(%s)" % r for r in regexes)
     elif regexes:
         return regexes[0]
     else:
     """Remove a file, and don't get annoyed if it doesn't exist."""
     try:
         os.remove(path)
-    except OSError:
-        _, e, _ = sys.exc_info()
+    except OSError as e:
         if e.errno != errno.ENOENT:
             raise
 

coverage/parser.py

 """Code parsing for Coverage."""
 
-import dis, re, sys, token, tokenize
+import collections, dis, re, token, tokenize
 
-from coverage.backward import set, sorted, StringIO # pylint: disable=W0622
+from coverage.backward import StringIO
 from coverage.backward import open_source, range    # pylint: disable=W0622
-from coverage.backward import reversed              # pylint: disable=W0622
 from coverage.backward import bytes_to_ints
 from coverage.bytecode import ByteCodes, CodeObjects
 from coverage.misc import nice_pair, expensive, join_regex
         self.text = text
         if not self.text:
             try:
-                sourcef = open_source(self.filename)
-                try:
+                with open_source(self.filename) as sourcef:
                     self.text = sourcef.read()
-                finally:
-                    sourcef.close()
-            except IOError:
-                _, err, _ = sys.exc_info()
+            except IOError as err:
                 raise NoSource(
                     "No source for code: '%s': %s" % (self.filename, err)
                     )
         # Lazily-created ByteParser
         self._byte_parser = None
 
-    def _get_byte_parser(self):
+    @property
+    def byte_parser(self):
         """Create a ByteParser on demand."""
         if not self._byte_parser:
             self._byte_parser = \
                             ByteParser(text=self.text, filename=self.filename)
         return self._byte_parser
-    byte_parser = property(_get_byte_parser)
 
     def lines_matching(self, *regexes):
         """Find the lines matching one of a list of regexes.
         """
         regex_c = re.compile(join_regex(regexes))
         matches = set()
-        for i, ltext in enumerate(self.lines):
+        for i, ltext in enumerate(self.lines, start=1):
             if regex_c.search(ltext):
-                matches.add(i+1)
+                matches.add(i)
         return matches
 
     def _raw_parse(self):
         """
         try:
             self._raw_parse()
-        except (tokenize.TokenError, IndentationError):
-            _, tokerr, _ = sys.exc_info()
+        except (tokenize.TokenError, IndentationError) as tokerr:
             msg, lineno = tokerr.args
             raise NotPython(
                 "Couldn't parse '%s' as Python source: '%s' at %s" %
 
         return lines, excluded_lines
 
+    @expensive
     def arcs(self):
         """Get information about the arcs available in the code.
 
             if fl1 != fl2:
                 all_arcs.append((fl1, fl2))
         return sorted(all_arcs)
-    arcs = expensive(arcs)
 
+    @expensive
     def exit_counts(self):
         """Get a mapping from line numbers to count of exits from that line.
 
 
         """
         excluded_lines = self.first_lines(self.excluded)
-        exit_counts = {}
+        exit_counts = collections.defaultdict(int)
         for l1, l2 in self.arcs():
             if l1 < 0:
                 # Don't ever report -1 as a line number
             if l2 in excluded_lines:
                 # Arcs to excluded lines shouldn't count.
                 continue
-            if l1 not in exit_counts:
-                exit_counts[l1] = 0
             exit_counts[l1] += 1
 
         # Class definitions have one extra exit, so remove one for each:
                 exit_counts[l] -= 1
 
         return exit_counts
-    exit_counts = expensive(exit_counts)
 
 
 ## Opcodes that guide the ByteParser.
         else:
             if not text:
                 assert filename, "If no code or text, need a filename"
-                sourcef = open_source(filename)
-                try:
+                with open_source(filename) as sourcef:
                     text = sourcef.read()
-                finally:
-                    sourcef.close()
             self.text = text
 
             try:
                 # Python 2.3 and 2.4 don't like partial last lines, so be sure
                 # the text ends nicely for them.
                 self.code = compile(text + '\n', filename, "exec")
-            except SyntaxError:
-                _, synerr, _ = sys.exc_info()
+            except SyntaxError as synerr:
                 raise NotPython(
                     "Couldn't parse '%s' as Python source: '%s' at line %d" %
                         (filename, synerr.msg, synerr.lineno)
 
         """
         children = CodeObjects(self.code)
-        return [ByteParser(code=c, text=self.text) for c in children]
+        return (ByteParser(code=c, text=self.text) for c in children)
 
     def _bytes_lines(self):
         """Map byte offsets to line numbers in `code`.
     def _block_stack_repr(self, block_stack):
         """Get a string version of `block_stack`, for debugging."""
         blocks = ", ".join(
-            ["(%s, %r)" % (dis.opname[b[0]], b[1]) for b in block_stack]
+            "(%s, %r)" % (dis.opname[b[0]], b[1]) for b in block_stack
         )
         return "[" + blocks + "]"
 
     def validate_chunks(self, chunks):
         """Validate the rule that chunks have a single entrance."""
         # starts is the entrances to the chunks
-        starts = set([ch.byte for ch in chunks])
+        starts = set(ch.byte for ch in chunks)
         for ch in chunks:
-            assert all([(ex in starts or ex < 0) for ex in ch.exits])
+            assert all((ex in starts or ex < 0) for ex in ch.exits)
 
     def _arcs(self):
         """Find the executable arcs in the code.
         chunks = self._split_into_chunks()
 
         # A map from byte offsets to chunks jumped into.
-        byte_chunks = dict([(c.byte, c) for c in chunks])
+        byte_chunks = dict((c.byte, c) for c in chunks)
 
         # There's always an entrance at the first chunk.
         yield (-1, byte_chunks[0].line)

coverage/phystokens.py

 """Better tokenizing for coverage.py."""
 
 import codecs, keyword, re, sys, token, tokenize
-from coverage.backward import set                       # pylint: disable=W0622
 from coverage.parser import generate_tokens
 
 
     # invalid charset, raise a SyntaxError.  Note that if a utf-8 bom is found,
     # 'utf-8-sig' is returned.
 
-    # If no encoding is specified, then the default will be returned.  The
-    # default varied with version.
-
-    if sys.version_info <= (2, 4):
-        default = 'iso-8859-1'
-    else:
-        default = 'ascii'
+    # If no encoding is specified, then the default will be returned.
+    default = 'ascii'
 
     bom_found = False
     encoding = None

coverage/results.py

 """Results of coverage measurement."""
 
+import collections
 import os
 
-from coverage.backward import iitems, set, sorted       # pylint: disable=W0622
+from coverage.backward import iitems
 from coverage.misc import format_lines, join_regex, NoSource
 from coverage.parser import CodeParser
 
             n_branches = self.total_branches()
             mba = self.missing_branch_arcs()
             n_partial_branches = sum(
-                [len(v) for k,v in iitems(mba) if k not in self.missing]
+                len(v) for k,v in iitems(mba) if k not in self.missing
                 )
-            n_missing_branches = sum([len(v) for k,v in iitems(mba)])
+            n_missing_branches = sum(len(v) for k,v in iitems(mba))
         else:
             n_branches = n_partial_branches = n_missing_branches = 0
             self.no_branch = set()
         """Returns a sorted list of the arcs actually executed in the code."""
         executed = self.coverage.data.executed_arcs(self.filename)
         m2fl = self.parser.first_line
-        executed = [(m2fl(l1), m2fl(l2)) for (l1,l2) in executed]
+        executed = ((m2fl(l1), m2fl(l2)) for (l1,l2) in executed)
         return sorted(executed)
 
     def arcs_missing(self):
         """Returns a sorted list of the arcs in the code not executed."""
         possible = self.arc_possibilities()
         executed = self.arcs_executed()
-        missing = [
+        missing = (
             p for p in possible
                 if p not in executed
                     and p[0] not in self.no_branch
-            ]
+        )
         return sorted(missing)
 
     def arcs_unpredicted(self):
         # Exclude arcs here which connect a line to itself.  They can occur
         # in executed data in some cases.  This is where they can cause
         # trouble, and here is where it's the least burden to remove them.
-        unpredicted = [
+        unpredicted = (
             e for e in executed
                 if e not in possible
                     and e[0] != e[1]
-            ]
+        )
         return sorted(unpredicted)
 
     def branch_lines(self):
     def total_branches(self):
         """How many total branches are there?"""
         exit_counts = self.parser.exit_counts()
-        return sum([count for count in exit_counts.values() if count > 1])
+        return sum(count for count in exit_counts.values() if count > 1)
 
     def missing_branch_arcs(self):
         """Return arcs that weren't executed from branch lines.
         """
         missing = self.arcs_missing()
         branch_lines = set(self.branch_lines())
-        mba = {}
+        mba = collections.defaultdict(list)
         for l1, l2 in missing:
             if l1 in branch_lines:
-                if l1 not in mba:
-                    mba[l1] = []
                 mba[l1].append(l2)
         return mba
 
         self.n_partial_branches = n_partial_branches
         self.n_missing_branches = n_missing_branches
 
+    @classmethod
     def set_precision(cls, precision):
         """Set the number of decimal places used to report percentages."""
         assert 0 <= precision < 10
         cls._precision = precision
         cls._near0 = 1.0 / 10**precision
         cls._near100 = 100.0 - cls._near0
-    set_precision = classmethod(set_precision)
 
-    def _get_n_executed(self):
+    @property
+    def n_executed(self):
         """Returns the number of executed statements."""
         return self.n_statements - self.n_missing
-    n_executed = property(_get_n_executed)
 
-    def _get_n_executed_branches(self):
+    @property
+    def n_executed_branches(self):
         """Returns the number of executed branches."""
         return self.n_branches - self.n_missing_branches
-    n_executed_branches = property(_get_n_executed_branches)
 
-    def _get_pc_covered(self):
+    @property
+    def pc_covered(self):
         """Returns a single percentage value for coverage."""
         if self.n_statements > 0:
             pc_cov = (100.0 * (self.n_executed + self.n_executed_branches) /
         else:
             pc_cov = 100.0
         return pc_cov
-    pc_covered = property(_get_pc_covered)
 
-    def _get_pc_covered_str(self):
+    @property
+    def pc_covered_str(self):
         """Returns the percent covered, as a string, without a percent sign.
 
         Note that "0" is only returned when the value is truly zero, and "100"
         else:
             pc = round(pc, self._precision)
         return "%.*f" % (self._precision, pc)
-    pc_covered_str = property(_get_pc_covered_str)
 
+    @classmethod
     def pc_str_width(cls):
         """How many characters wide can pc_covered_str be?"""
         width = 3   # "100"
         if cls._precision > 0:
             width += 1 + cls._precision
         return width
-    pc_str_width = classmethod(pc_str_width)
 
     def __add__(self, other):
         nums = Numbers()

coverage/templite.py

 
 import re
 
-from coverage.backward import set                       # pylint: disable=W0622
-
 
 class CodeBuilder(object):
     """Build source code conveniently."""

coverage/version.py

 """The version and URL for coverage.py"""
 # This file is exec'ed in setup.py, don't import anything!
 
-__version__ = "3.7.1"                   # see detailed history in CHANGES.txt
+__version__ = "4.0a0"                   # see detailed history in CHANGES.txt
 
 __url__ = "http://nedbatchelder.com/code/coverage"
 if max(__version__).isalpha():

coverage/xmlreport.py

 import xml.dom.minidom
 
 from coverage import __url__, __version__
-from coverage.backward import sorted, rpartition    # pylint: disable=W0622
 from coverage.report import Reporter
 
 def rate(hit, num):
 
         # Create the 'lines' and 'package' XML elements, which
         # are populated later.  Note that a package == a directory.
-        package_name = rpartition(cu.name, ".")[0]
+        package_name = cu.name.rpartition(".")[0]
         className = cu.name
 
         package = self.packages.setdefault(package_name, [{}, 0, 0, 0, 0])
         class_hits = class_lines - len(analysis.missing)
 
         if self.arcs:
-            class_branches = sum([t for t,k in branch_stats.values()])
-            missing_branches = sum([t-k for t,k in branch_stats.values()])
+            class_branches = sum(t for t, k in branch_stats.values())
+            missing_branches = sum(t - k for t, k in branch_stats.values())
             class_br_hits = class_branches - missing_branches
         else:
             class_branches = 0.0

doc/_ext/px_cleaner.py

 def clean_px(fname):
     """Clean a px file."""
 
-    f = open(fname)
-    try:
+    with open(fname) as f:
         text = f.read()
-    finally:
-        f.close()
     text = text.lstrip()
-    f = open(fname, "w")
-    try:
+    with open(fname, "w") as f:
         f.write(text)
-    finally:
-        f.close()
 
 def clean_px_files(fnames):
     for fname in fnames:
 
 if __name__ == '__main__':
     clean_px_files(sys.argv[1:])
-
     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:
+    with open(pth_path, "w") as pth_file:
         pth_file.write("import coverage; coverage.process_startup()\n")
-    finally:
-        pth_file.close()
 
     version = "%s%s" % sys.version_info[:2]
     suffix = "%s_%s_%s" % (version, tracer, socket.gethostname())
         checked.add(fname)
 
         line = None
-        for n, line in enumerate(open(fname, "rb")):
+        for n, line in enumerate(open(fname, "rb"), start=1):
             if crlf:
                 if "\r" in line:
-                    print("%s@%d: CR found" % (fname, n+1))
+                    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+1))
+                    print("%s@%d: trailing whitespace found" % (fname, n))
                     return
 
         if line is not None and not line.strip():
 
     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 pypy_version)
 
     print('=== %s %s %s (%s) ===' % (impl, version, label, sys.executable))
 
     def one_file(self, options, filename):
         """Process just one file."""
 
-        if options.dis or options.chunks:
-            try:
-                bp = ByteParser(filename=filename)
-            except CoverageException:
-                _, err, _ = sys.exc_info()
-                print("%s" % (err,))
-                return
+        try:
+            bp = ByteParser(filename=filename)
+        except CoverageException as err:
+            print("%s" % (err,))
+            return
 
         if options.dis:
             print("Main code:")
 
                 exit_counts = cp.exit_counts()
 
-                for i, ltext in enumerate(cp.lines):
-                    lineno = i+1
+                for lineno, ltext in enumerate(cp.lines, start=1):
                     m0 = m1 = m2 = m3 = a = ' '
                     if lineno in cp.statement_starts:
                         m0 = '-'
 the code analysis tools and tracing hooks provided in the Python standard
 library to determine which lines are executable, and which have been executed.
 
-Coverage.py runs on Pythons 2.3 through 3.3, and PyPy 1.9.
+Coverage.py runs on Pythons 2.6, 2.7, 3.2, 3.3, and PyPy 1.9.
 
 Documentation is at `nedbatchelder.com <%s>`_.  Code repository and issue
 tracker are on `Bitbucket <http://bitbucket.org/ned/coveragepy>`_, with a
 __version__ = __url__ = ""      # Keep pylint happy.
 
 cov_ver_py = os.path.join(os.path.split(__file__)[0], "coverage/version.py")
-version_file = open(cov_ver_py)
-try:
+with open(cov_ver_py) as version_file:
     exec(compile(version_file.read(), cov_ver_py, 'exec'))
-finally:
-    version_file.close()
 
 doclines = (doc % __url__).splitlines()
 classifier_list = classifiers.splitlines()
     errors.DistutilsExecError,
     errors.DistutilsPlatformError,
 )
-if sys.platform == 'win32' and sys.version_info > (2, 6):
-    # 2.6's distutils.msvc9compiler can raise an IOError when failing to
+if sys.platform == 'win32':
+    # distutils.msvc9compiler can raise an IOError when failing to
     # find the compiler
     ext_errors += (IOError,)
 
             build_ext.build_extension(self, ext)
         except ext_errors:
             raise BuildFailed()
-        except ValueError:
+        except ValueError as err:
             # this can happen on Windows 64 bit, see Python issue 7511
-            if "'path'" in str(sys.exc_info()[1]): # works with both py 2/3
+            if "'path'" in str(err): # works with both py 2/3
                 raise BuildFailed()
             raise
 
     # extension.  Try it with, and if it fails, try it without.
     try:
         setup(**setup_args)
-    except BuildFailed:
+    except BuildFailed as exc:
         msg = "Couldn't install with extension module, trying without it..."
-        exc = sys.exc_info()[1]
         exc_msg = "%s: %s" % (exc.__class__.__name__, exc.cause)
         print("**\n** %s\n** %s\n**" % (msg, exc_msg))
 

tests/backunittest.py

 """Implementations of unittest features from the future."""
 
-import difflib, re, sys, unittest
-
-from coverage.backward import set                   # pylint: disable=W0622
+import difflib, re, unittest
 
 
 def _need(method):
     the builtin `unittest` doesn't have them.
 
     """
-    if _need('assertTrue'):
-        def assertTrue(self, exp, msg=None):
-            """Assert that `exp` is true."""
-            if not exp:
-                self.fail(msg)
-
-    if _need('assertFalse'):
-        def assertFalse(self, exp, msg=None):
-            """Assert that `exp` is false."""
-            if exp:
-                self.fail(msg)
-
     if _need('assertIn'):
         def assertIn(self, member, container, msg=None):
             """Assert that `member` is in `container`."""
             """
             try:
                 callobj(*args, **kw)
-            except excClass:
-                _, exc, _ = sys.exc_info()
+            except excClass as exc:
                 excMsg = str(exc)
                 if re.search(regexp, excMsg):
                     # Message provided, and we got the right one: it passes.

tests/coveragetest.py

 """Base test case class for coverage testing."""
 
 import glob, imp, os, random, shlex, shutil, sys, tempfile, textwrap
-import atexit
+import atexit, collections
 
 import coverage
-from coverage.backward import sorted, StringIO      # pylint: disable=W0622
-from coverage.backward import to_bytes
+from coverage.backward import StringIO, to_bytes
 from coverage.control import _TEST_NAME_FILE
 from tests.backtest import run_command
 from tests.backunittest import TestCase
             os.makedirs(dirs)
 
         # Create the file.
-        f = open(filename, 'wb')
-        try:
+        with open(filename, 'wb') as f:
             f.write(to_bytes(text))
-        finally:
-            f.close()
 
         return filename
 
 
         """
         modfile = modname + '.py'
-        f = open(modfile, 'r')
 
         for suff in imp.get_suffixes():
             if suff[0] == '.py':
                 break
-        try:
+
+        with open(modfile, 'r') as f:
             # pylint: disable=W0631
             # (Using possibly undefined loop variable 'suff')
             mod = imp.load_module(modname, f, modfile, suff)
-        finally:
-            f.close()
+
         return mod
 
     def start_import_stop(self, cov, modname):
 
     # Map chars to numbers for arcz_to_arcs
     _arcz_map = {'.': -1}
-    _arcz_map.update(dict([(c, ord(c)-ord('0')) for c in '123456789']))
+    _arcz_map.update(dict((c, ord(c)-ord('0')) for c in '123456789'))
     _arcz_map.update(dict(
-        [(c, 10+ord(c)-ord('A')) for c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ']
-        ))
+        (c, 10+ord(c)-ord('A')) for c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+    ))
 
     def arcz_to_arcs(self, arcz):
         """Convert a compact textual representation of arcs to a list of pairs.
     def assertEqualArcs(self, a1, a2, msg=None):
         """Assert that the arc lists `a1` and `a2` are equal."""
         # Make them into multi-line strings so we can see what's going wrong.
-        s1 = "\n".join([repr(a) for a in a1]) + "\n"
-        s2 = "\n".join([repr(a) for a in a2]) + "\n"
+        s1 = "\n".join(repr(a) for a in a1) + "\n"
+        s2 = "\n".join(repr(a) for a in a2) + "\n"
         self.assertMultiLineEqual(s1, s2, msg)
 
     def check_coverage(self, text, lines=None, missing="", report="",
             self.test_method_made_any_files = False
 
     # Map from class to info about how it ran.
-    class_behaviors = {}
+    class_behaviors = collections.defaultdict(ClassBehavior)
 
+    @classmethod
     def report_on_class_behavior(cls):
         """Called at process exit to report on class behavior."""
         for test_class, behavior in cls.class_behaviors.items():
                         where,
                     )
                 )
-    report_on_class_behavior = classmethod(report_on_class_behavior)
 
     def class_behavior(self):
         """Get the ClassBehavior instance for this test."""
-        cls = self.__class__
-        if cls not in self.class_behaviors:
-            self.class_behaviors[cls] = self.ClassBehavior()
-        return self.class_behaviors[cls]
+        return self.class_behaviors[self.__class__]
 
 
 # When the process ends, find out about bad classes.

tests/farm/html/run_partial.py

 contains("html_partial/index.html",
     "<a href='partial.html'>partial</a>",
     )
-if sys.version_info >= (2, 4):
-    contains("html_partial/index.html",
-        "<span class='pc_cov'>100%</span>"
-        )
+contains("html_partial/index.html",
+    "<span class='pc_cov'>100%</span>"
+    )
 
 clean("html_partial")
 
 import sys
 
-if sys.version_info >= (2, 5) and sys.platform == 'win32':
+if sys.platform == 'win32':
     # Windows implementation
     def process_ram():
         """How much RAM is this process using? (Windows)"""
         """Read the /proc/PID/status file to find memory use."""
         try:
             # get pseudo file /proc/<pid>/status
-            t = open('/proc/%d/status' % os.getpid())
-            try:
+            with open('/proc/%d/status' % os.getpid()) as t:
                 v = t.read()
-            finally:
-                t.close()
         except IOError:
             return 0    # non-Linux?
          # get VmKey line e.g. 'VmRSS:  9999  kB\n ...'

tests/test_arcs.py

             arcz=".1 14 45 5.  .2 2. 23 3.", arcz_missing="23 3.")
 
     def test_multiline(self):
-        # The firstlineno of the a assignment below differs among Python
-        # versions.
-        if sys.version_info >= (2, 5):
-            arcz = ".1 15 5-2"
-        else:
-            arcz = ".1 15 5-1"
         self.check_coverage("""\
             a = (
                 2 +
             b = \\
                 6
             """,
-            arcz=arcz, arcz_missing="")
+            arcz=".1 15 5-2", arcz_missing="")
 
     def test_if_return(self):
         self.check_coverage("""\
                 )
 
 
-if sys.version_info >= (2, 6):
-    class WithTest(CoverageTest):
-        """Arc-measuring tests involving context managers."""
+class WithTest(CoverageTest):
+    """Arc-measuring tests involving context managers."""
 
-        def test_with(self):
-            self.check_coverage("""\
-                def example():
-                    with open("test", "w") as f: # exit
-                        f.write("")
-                        return 1
+    def test_with(self):
+        self.check_coverage("""\
+            def example():
+                with open("test", "w") as f: # exit
+                    f.write("")
+                    return 1
 
-                example()
-                """,
-                arcz=".1 .2 23 34 4. 16 6."
-                )
+            example()
+            """,
+            arcz=".1 .2 23 34 4. 16 6."
+            )
 
-        def test_bug_146(self):
-            # https://bitbucket.org/ned/coveragepy/issue/146
-            self.check_coverage("""\
-                for i in range(2):
-                    with open("test", "w") as f:
-                        print(3)
-                    print(4)
-                print(5)
-                """,
-                arcz=".1 12 23 34 41 15 5."
-                )
+    def test_bug_146(self):
+        # https://bitbucket.org/ned/coveragepy/issue/146
+        self.check_coverage("""\
+            for i in range(2):
+                with open("test", "w") as f:
+                    print(3)
+                print(4)
+            print(5)
+            """,
+            arcz=".1 12 23 34 41 15 5."
+            )
 
 
 class LoopArcTest(CoverageTest):
             arcz=".1 12 23 35 56 61 17 7.",
             arcz_missing="", arcz_unpredicted="")
 
-    # Run this test only on 2.6 and 2.7 for now.  I hope to fix it on Py3
+    # Run this test only on Py2 for now.  I hope to fix it on Py3
     # eventually...
-    if (2, 6) <= sys.version_info < (3,):
+    if sys.version_info < (3, 0):
         # "except Exception as e" is crucial here.
         def test_bug_212(self):
             self.check_coverage("""\
                 arcz=".1 .2 1A 23 34 56 67 68 8. AB BC C. DE E.",
                 arcz_missing="C.", arcz_unpredicted="45 7. CD")
 
-    if sys.version_info >= (2, 5):
-        # Try-except-finally was new in 2.5
-        def test_except_finally(self):
-            self.check_coverage("""\
-                a, b, c = 1, 1, 1
-                try:
-                    a = 3
-                except:
-                    b = 5
-                finally:
-                    c = 7
-                assert a == 3 and b == 1 and c == 7
-                """,
-                arcz=".1 12 23 45 37 57 78 8.", arcz_missing="45 57")
-            self.check_coverage("""\
-                a, b, c = 1, 1, 1
-                def oops(x):
-                    if x % 2: raise Exception("odd")
-                try:
-                    a = 5
-                    oops(1)
-                    a = 7
-                except:
-                    b = 9
-                finally:
-                    c = 11
-                assert a == 5 and b == 9 and c == 11
-                """,
-                arcz=".1 12 .3 3-2 24 45 56 67 7B 89 9B BC C.",
-                arcz_missing="67 7B", arcz_unpredicted="68")
+    def test_except_finally(self):
+        self.check_coverage("""\
+            a, b, c = 1, 1, 1
+            try:
+                a = 3
+            except:
+                b = 5
+            finally:
+                c = 7
+            assert a == 3 and b == 1 and c == 7
+            """,
+            arcz=".1 12 23 45 37 57 78 8.", arcz_missing="45 57")
+        self.check_coverage("""\
+            a, b, c = 1, 1, 1
+            def oops(x):
+                if x % 2: raise Exception("odd")
+            try:
+                a = 5
+                oops(1)
+                a = 7
+            except:
+                b = 9
+            finally:
+                c = 11
+            assert a == 5 and b == 9 and c == 11
+            """,
+            arcz=".1 12 .3 3-2 24 45 56 67 7B 89 9B BC C.",
+            arcz_missing="67 7B", arcz_unpredicted="68")
 
 
 class MiscArcTest(CoverageTest):

tests/test_collector.py

 
 import coverage
 from coverage.backward import StringIO
-from coverage.backward import set                   # pylint: disable=W0622
 
 from tests.coveragetest import CoverageTest
 
         # duplicates.
         trace_lines = [
             l for l in debug_out.getvalue().splitlines()
-            if l.startswith("Tracing ") or l.startswith("Not tracing ")
+            if l.startswith(("Tracing ", "Not tracing "))
         ]
         filenames = [re.search(r"'[^']+'", l).group() for l in trace_lines]
         self.assertEqual(len(filenames), len(set(filenames)))

tests/test_config.py

 # -*- coding: utf-8 -*-
 """Test the config file handling for coverage.py"""
 
-import sys
 import coverage
 from coverage.misc import CoverageException
 
             'other': ['other', '/home/ned/other', 'c:\\Ned\\etc']
             })
 
-    if sys.version_info[:2] != (3,1):
-        def test_one(self):
-            # This sample file tries to use lots of variation of syntax...
-            self.make_file(".coveragerc", """\
-                [html]
-                title = tabblo & «ταБЬℓσ» # numbers
-                """)
-            cov = coverage.coverage()
+    def test_one(self):
+        # This sample file tries to use lots of variation of syntax...
+        self.make_file(".coveragerc", """\
+            [html]
+            title = tabblo & «ταБЬℓσ» # numbers
+            """)
+        cov = coverage.coverage()
 
-            self.assertEqual(cov.config.html_title,
-                "tabblo & «ταБЬℓσ» # numbers"
-                )
+        self.assertEqual(cov.config.html_title,
+            "tabblo & «ταБЬℓσ» # numbers"
+            )

tests/test_coverage.py

             """,
             [1,2,4,5,7,9,10], "4, 7")
 
-    if sys.version_info >= (2, 4):
-        # In 2.4 and up, constant if's were compiled away.
-        def test_constant_if(self):
-            self.check_coverage("""\
-                if 1:
-                    a = 2
-                assert a == 2
-                """,
-                [2,3], "")
+    def test_constant_if(self):
+        self.check_coverage("""\
+            if 1:
+                a = 2
+            assert a == 2
+            """,
+            [2,3], "")
 
     def test_while(self):
         self.check_coverage("""\
             [8,9], "", excludes=['#pragma: NO COVER'])
 
 
-if sys.version_info >= (2, 4):
-    class Py24Test(CoverageTest):
-        """Tests of new syntax in Python 2.4."""
+class Py24Test(CoverageTest):
+    """Tests of new syntax in Python 2.4."""
 
-        def test_function_decorators(self):
-            self.check_coverage("""\
-                def require_int(func):
+    def test_function_decorators(self):
+        self.check_coverage("""\
+            def require_int(func):
+                def wrapper(arg):
+                    assert isinstance(arg, int)
+                    return func(arg)
+
+                return wrapper
+
+            @require_int
+            def p1(arg):
+                return arg*2
+
+            assert p1(10) == 20
+            """,
+            [1,2,3,4,6,8,10,12], "")
+
+    def test_function_decorators_with_args(self):
+        self.check_coverage("""\
+            def boost_by(extra):
+                def decorator(func):
                     def wrapper(arg):
-                        assert isinstance(arg, int)
-                        return func(arg)
+                        return extra*func(arg)
+                    return wrapper
+                return decorator
 
+            @boost_by(10)
+            def boosted(arg):
+                return arg*2
+
+            assert boosted(10) == 200
+            """,
+            [1,2,3,4,5,6,8,10,12], "")
+
+    def test_double_function_decorators(self):
+        self.check_coverage("""\
+            def require_int(func):
+                def wrapper(arg):
+                    assert isinstance(arg, int)
+                    return func(arg)
+                return wrapper
+
+            def boost_by(extra):
+                def decorator(func):
+                    def wrapper(arg):
+                        return extra*func(arg)
                     return wrapper
+                return decorator
 
-                @require_int
-                def p1(arg):
-                    return arg*2
+            @require_int
+            @boost_by(10)
+            def boosted1(arg):
+                return arg*2
 
-                assert p1(10) == 20
-                """,
-                [1,2,3,4,6,8,10,12], "")
+            assert boosted1(10) == 200
 
-        def test_function_decorators_with_args(self):
-            self.check_coverage("""\
-                def boost_by(extra):
-                    def decorator(func):
-                        def wrapper(arg):
-                            return extra*func(arg)
-                        return wrapper
-                    return decorator
+            @boost_by(10)
+            @require_int
+            def boosted2(arg):
+                return arg*2
 
-                @boost_by(10)
-                def boosted(arg):
-                    return arg*2
+            assert boosted2(10) == 200
+            """,
+            ([1,2,3,4,5,7,8,9,10,11,12,14,15,17,19,21,22,24,26],
+                [1,2,3,4,5,7,8,9,10,11,12,14,   17,19,21,   24,26]), "")
 
-                assert boosted(10) == 200
-                """,
-                [1,2,3,4,5,6,8,10,12], "")
 
-        def test_double_function_decorators(self):
-            self.check_coverage("""\
-                def require_int(func):
-                    def wrapper(arg):
-                        assert isinstance(arg, int)
-                        return func(arg)
-                    return wrapper
+class Py25Test(CoverageTest):
+    """Tests of new syntax in Python 2.5."""
 
-                def boost_by(extra):
-                    def decorator(func):
-                        def wrapper(arg):
-                            return extra*func(arg)
-                        return wrapper
-                    return decorator
+    def test_with_statement(self):
+        self.check_coverage("""\
+            from __future__ import with_statement
 
-                @require_int
-                @boost_by(10)
-                def boosted1(arg):
-                    return arg*2
+            class Managed:
+                def __enter__(self):
+                    desc = "enter"
 
-                assert boosted1(10) == 200
+                def __exit__(self, type, value, tb):
+                    desc = "exit"
 
-                @boost_by(10)
-                @require_int
-                def boosted2(arg):
-                    return arg*2
+            m = Managed()
+            with m:
+                desc = "block1a"
+                desc = "block1b"
 
-                assert boosted2(10) == 200
-                """,
-                ([1,2,3,4,5,7,8,9,10,11,12,14,15,17,19,21,22,24,26],
-                 [1,2,3,4,5,7,8,9,10,11,12,14,   17,19,21,   24,26]), "")
+            try:
+                with m:
+                    desc = "block2"
+                    raise Exception("Boo!")
+            except:
+                desc = "caught"
+            """,
+            [1,3,4,5,7,8,10,11,12,13,15,16,17,18,19,20], "")
 
-
-if sys.version_info >= (2, 5):
-    class Py25Test(CoverageTest):
-        """Tests of new syntax in Python 2.5."""
-
-        def test_with_statement(self):
-            self.check_coverage("""\
-                from __future__ import with_statement
-
-                class Managed:
-                    def __enter__(self):
-                        desc = "enter"
-
-                    def __exit__(self, type, value, tb):
-                        desc = "exit"
-
-                m = Managed()
-                with m:
-                    desc = "block1a"
-                    desc = "block1b"
-
-                try:
-                    with m:
-                        desc = "block2"
-                        raise Exception("Boo!")
-                except:
-                    desc = "caught"
-                """,
-                [1,3,4,5,7,8,10,11,12,13,15,16,17,18,19,20], "")
-
-        def test_try_except_finally(self):
-            self.check_coverage("""\
-                a = 0; b = 0
-                try:
-                    a = 1
-                except:
-                    a = 99
-                finally:
-                    b = 2
-                assert a == 1 and b == 2
-                """,
-                [1,2,3,4,5,7,8], "4-5")
-            self.check_coverage("""\
-                a = 0; b = 0
-                try:
-                    a = 1
-                    raise Exception("foo")
-                except:
-                    a = 99
-                finally:
-                    b = 2
-                assert a == 99 and b == 2
-                """,
-                [1,2,3,4,5,6,8,9], "")
-            self.check_coverage("""\
-                a = 0; b = 0
-                try:
-                    a = 1
-                    raise Exception("foo")
-                except ImportError:
-                    a = 99
-                except:
-                    a = 123
-                finally:
-                    b = 2
-                assert a == 123 and b == 2
-                """,
-                [1,2,3,4,5,6,7,8,10,11], "6")
-            self.check_coverage("""\
-                a = 0; b = 0
-                try:
-                    a = 1
-                    raise IOError("foo")
-                except ImportError:
-                    a = 99
-                except IOError:
-                    a = 17
-                except:
-                    a = 123
-                finally:
-                    b = 2
-                assert a == 17 and b == 2
-                """,
-                [1,2,3,4,5,6,7,8,9,10,12,13], "6, 9-10")
-            self.check_coverage("""\
-                a = 0; b = 0
-                try:
-                    a = 1
-                except:
-                    a = 99
-                else:
-                    a = 123
-                finally:
-                    b = 2
-                assert a == 123 and b == 2
-                """,
-                [1,2,3,4,5,7,9,10], "4-5")
-            self.check_coverage("""\
-                a = 0; b = 0
-                try:
-                    a = 1
-                    raise Exception("foo")
-                except:
-                    a = 99
-                else:
-                    a = 123
-                finally:
-                    b = 2
-                assert a == 99 and b == 2
-                """,
-                [1,2,3,4,5,6,8,10,11], "8")
+    def test_try_except_finally(self):
+        self.check_coverage("""\
+            a = 0; b = 0
+            try:
+                a = 1
+            except:
+                a = 99
+            finally:
+                b = 2
+            assert a == 1 and b == 2
+            """,
+            [1,2,3,4,5,7,8], "4-5")
+        self.check_coverage("""\
+            a = 0; b = 0
+            try:
+                a = 1
+                raise Exception("foo")
+            except:
+                a = 99
+            finally:
+                b = 2
+            assert a == 99 and b == 2
+            """,
+            [1,2,3,4,5,6,8,9], "")
+        self.check_coverage("""\
+            a = 0; b = 0
+            try:
+                a = 1
+                raise Exception("foo")
+            except ImportError:
+                a = 99
+            except:
+                a = 123
+            finally:
+                b = 2
+            assert a == 123 and b == 2
+            """,
+            [1,2,3,4,5,6,7,8,10,11], "6")
+        self.check_coverage("""\
+            a = 0; b = 0
+            try:
+                a = 1
+                raise IOError("foo")
+            except ImportError:
+                a = 99
+            except IOError:
+                a = 17
+            except:
+                a = 123
+            finally:
+                b = 2
+            assert a == 17 and b == 2
+            """,
+            [1,2,3,4,5,6,7,8,9,10,12,13], "6, 9-10")
+        self.check_coverage("""\
+            a = 0; b = 0
+            try:
+                a = 1
+            except:
+                a = 99
+            else:
+                a = 123
+            finally:
+                b = 2
+            assert a == 123 and b == 2
+            """,
+            [1,2,3,4,5,7,9,10], "4-5")
+        self.check_coverage("""\
+            a = 0; b = 0
+            try:
+                a = 1
+                raise Exception("foo")
+            except:
+                a = 99
+            else:
+                a = 123
+            finally:
+                b = 2
+            assert a == 99 and b == 2
+            """,
+            [1,2,3,4,5,6,8,10,11], "8")
 
 
 class ModuleTest(CoverageTest):

tests/test_data.py

         covdata.add_line_data(DATA_1)
         covdata.write()
 
-        fdata = open(".coverage", 'rb')
-        try:
+        with open(".coverage", 'rb') as fdata:
             data = pickle.load(fdata)
-        finally:
-            fdata.close()
 
         lines = data['lines']
         self.assertSameElements(lines.keys(), MEASURED_FILES_1)
         covdata.add_arc_data(ARC_DATA_3)
         covdata.write()
 
-        fdata = open(".coverage", 'rb')
-        try:
+        with open(".coverage", 'rb') as fdata:
             data = pickle.load(fdata)
-        finally:
-            fdata.close()
 
         self.assertSameElements(data['lines'].keys(), [])
         arcs = data['arcs']

tests/test_execfile.py

         # Make sure we can read any sort of line ending.
         pylines = """# try newlines|print('Hello, world!')|""".split('|')
         for nl in ('\n', '\r\n', '\r'):
-            fpy = open('nl.py', 'wb')
-            try:
+            with open('nl.py', 'wb') as fpy:
                 fpy.write(nl.join(pylines).encode('utf-8'))
-            finally:
-                fpy.close()
             run_python_file('nl.py', ['nl.py'])
         self.assertEqual(self.stdout(), "Hello, world!\n"*3)
 

tests/test_farm.py

             copy run runfunc compare contains doesnt_contain clean skip
             """.split()
         if self.clean_only:
-            glo = dict([(fn, self.noop) for fn in fns])
+            glo = dict((fn, self.noop) for fn in fns)
             glo['clean'] = self.clean
         else:
-            glo = dict([(fn, getattr(self, fn)) for fn in fns])
+            glo = dict((fn, getattr(self, fn)) for fn in fns)
             if self.dont_clean:                 # pragma: not covered
                 glo['clean'] = self.noop
 

tests/test_files.py

 
 from coverage.files import FileLocator, TreeMatcher, FnmatchMatcher
 from coverage.files import PathAliases, find_python_files, abs_file
-from coverage.backward import set                   # pylint: disable=W0622
 from coverage.misc import CoverageException
 
 from tests.coveragetest import CoverageTest

tests/test_html.py

         self.assertIn("<title>Metrics &amp; stuff!</title>", index)
         self.assertIn("<h1>Metrics &amp; stuff!:", index)
 
-    if sys.version_info[:2] != (3,1):
-        def test_non_ascii_title_set_in_config_file(self):
-            self.create_initial_files()
-            self.make_file(".coveragerc",
-                "[html]\ntitle = «ταБЬℓσ» numbers"
-                )
-            self.run_coverage()
-            index = open("htmlcov/index.html").read()
-            self.assertIn(
-                "<title>&#171;&#964;&#945;&#1041;&#1068;&#8467;&#963;&#187;"
-                " numbers", index
-                )
-            self.assertIn(
-                "<h1>&#171;&#964;&#945;&#1041;&#1068;&#8467;&#963;&#187;"
-                " numbers", index
-                )
+    def test_non_ascii_title_set_in_config_file(self):
+        self.create_initial_files()
+        self.make_file(".coveragerc",
+            "[html]\ntitle = «ταБЬℓσ» numbers"
+            )
+        self.run_coverage()
+        index = open("htmlcov/index.html").read()
+        self.assertIn(
+            "<title>&#171;&#964;&#945;&#1041;&#1068;&#8467;&#963;&#187;"
+            " numbers", index
+            )
+        self.assertIn(
+            "<h1>&#171;&#964;&#945;&#1041;&#1068;&#8467;&#963;&#187;"
+            " numbers", index
+            )
 
     def test_title_set_in_args(self):
         self.create_initial_files()

tests/test_oddball.py

             self.assertEqual(clean_lines, lines_expected)
 
 
-if sys.version_info >= (2, 5):
-    class DoctestTest(CoverageTest):
-        """Tests invoked with doctest should measure properly."""
+class DoctestTest(CoverageTest):
+    """Tests invoked with doctest should measure properly."""
 
-        def setUp(self):
-            super(DoctestTest, self).setUp()
+    def setUp(self):
+        super(DoctestTest, self).setUp()
 
-            # Oh, the irony!  This test case exists because Python 2.4's
-            # doctest module doesn't play well with coverage.  But nose fixes
-            # the problem by monkeypatching doctest.  I want to undo the
-            # monkeypatch to be sure I'm getting the doctest module that users
-            # of coverage will get.  Deleting the imported module here is
-            # enough: when the test imports doctest again, it will get a fresh
-            # copy without the monkeypatch.
-            del sys.modules['doctest']
+        # Oh, the irony!  This test case exists because Python 2.4's
+        # doctest module doesn't play well with coverage.  But nose fixes
+        # the problem by monkeypatching doctest.  I want to undo the
+        # monkeypatch to be sure I'm getting the doctest module that users
+        # of coverage will get.  Deleting the imported module here is
+        # enough: when the test imports doctest again, it will get a fresh
+        # copy without the monkeypatch.
+        del sys.modules['doctest']
 
-        def test_doctest(self):
-            self.check_coverage('''\
-                def return_arg_or_void(arg):
-                    """If <arg> is None, return "Void"; otherwise return <arg>
+    def test_doctest(self):
+        self.check_coverage('''\
+            def return_arg_or_void(arg):
+                """If <arg> is None, return "Void"; otherwise return <arg>
 
-                    >>> return_arg_or_void(None)
-                    'Void'
-                    >>> return_arg_or_void("arg")
-                    'arg'
-                    >>> return_arg_or_void("None")
-                    'None'
-                    """
-                    if arg is None:
-                        return "Void"
-                    else:
-                        return arg
+                >>> return_arg_or_void(None)
+                'Void'
+                >>> return_arg_or_void("arg")
+                'arg'
+                >>> return_arg_or_void("None")
+                'None'
+                """
+                if arg is None:
+                    return "Void"
+                else:
+                    return arg
 
-                import doctest, sys
-                doctest.testmod(sys.modules[__name__])  # we're not __main__ :(
-                ''',
-                [1,11,12,14,16,17], "")
+            import doctest, sys
+            doctest.testmod(sys.modules[__name__])  # we're not __main__ :(
+            ''',
+            [1,11,12,14,16,17], "")
 
 
 if hasattr(sys, 'gettrace'):

tests/test_phystokens.py

         """Tokenize `source`, then put it back together, should be the same."""
         tokenized = ""
         for line in source_token_lines(source):
-            text = "".join([t for _,t in line])
+            text = "".join(t for _, t in line)
             tokenized += text + "\n"
         # source_token_lines doesn't preserve trailing spaces, so trim all that
         # before comparing.
 
         run_in_temp_dir = False
 
-        if sys.version_info >= (2,4):
-            default_encoding = 'ascii'
-        else:
-            default_encoding = 'iso-8859-1'
-
         def test_detect_source_encoding(self):
             # Various forms from http://www.python.org/dev/peps/pep-0263/
             source = "# coding=cp850\n\n"
         def test_dont_detect_source_encoding_on_third_line(self):
             # A coding declaration doesn't count on the third line.
             source = "\n\n# coding=cp850\n\n"
-            self.assertEqual(source_encoding(source), self.default_encoding)
+            self.assertEqual(source_encoding(source), 'ascii')
 
         def test_detect_source_encoding_of_empty_file(self):
             # An important edge case.
-            self.assertEqual(source_encoding(""), self.default_encoding)
+            self.assertEqual(source_encoding(""), 'ascii')
 
         def test_bom(self):
             # A BOM means utf-8.

tests/test_process.py

             import covmod1
             import covmodzip1
             a = 1
-            print ('done')
+            print('done')
             """)
 
         self.assert_doesnt_exist(".coverage")
             else:
                 c = 1
             d = 1
-            print ('done')
+            print('done')
             """)
 
         out = self.run_command("coverage -x -p b_or_c.py b")
             else:
                 c = 1
             d = 1
-            print ('done')
+            print('done')
             """)
 
         out = self.run_command("coverage -x -p b_or_c.py b")
             else:
                 c = 1
             d = 1
-            print ('done')
+            print('done')
             """)
 
         self.make_file(".coveragerc", """\
         if '__pypy__' in sys.builtin_module_names:
             # Pypy has an extra frame in the traceback for some reason
             lines2 = out2.splitlines()
-            out2 = "".join([l+"\n" for l in lines2 if "toplevel" not in l])
+            out2 = "".join(l+"\n" for l in lines2 if "toplevel" not in l)
         self.assertMultiLineEqual(out, out2)