[Python-checkins] cpython (merge default -> default): Merge

antoine.pitrou python-checkins at python.org
Wed Jul 31 21:54:29 CEST 2013


http://hg.python.org/cpython/rev/3a7dedc7067f
changeset:   84935:3a7dedc7067f
parent:      84934:e4594c7dfeeb
parent:      84932:8327780d3841
user:        Antoine Pitrou <solipsis at pitrou.net>
date:        Wed Jul 31 21:54:18 2013 +0200
summary:
  Merge

files:
  .hgignore                       |   5 ++
  Doc/library/aifc.rst            |   3 +-
  Doc/library/difflib.rst         |   2 +-
  Doc/library/email.iterators.rst |   2 +-
  Doc/library/email.policy.rst    |   2 +-
  Doc/library/enum.rst            |  10 ++--
  Doc/library/unittest.rst        |   6 +-
  Doc/library/wave.rst            |   5 ++
  Doc/tutorial/inputoutput.rst    |  13 +++-
  Doc/whatsnew/3.4.rst            |   5 +-
  Lib/test/test_wave.py           |  29 ++++++++----
  Lib/wave.py                     |  13 +++++
  Makefile.pre.in                 |  49 ++++++++++++++++++++-
  Misc/NEWS                       |   6 ++
  Modules/_io/iobase.c            |   4 +-
  Modules/_sha3/sha3module.c      |   4 +-
  Modules/_testcapimodule.c       |  11 ++++
  17 files changed, 137 insertions(+), 32 deletions(-)


diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -36,6 +36,7 @@
 Modules/config.c
 Modules/ld_so_aix$
 Parser/pgen$
+^lcov-report/
 ^core
 ^python-gdb.py
 ^python.exe-gdb.py
@@ -91,3 +92,7 @@
 .coverage
 coverage/
 htmlcov/
+*.gcda
+*.gcno
+*.gcov
+coverage.info
diff --git a/Doc/library/aifc.rst b/Doc/library/aifc.rst
--- a/Doc/library/aifc.rst
+++ b/Doc/library/aifc.rst
@@ -51,7 +51,8 @@
    used for writing, the file object should be seekable, unless you know ahead of
    time how many samples you are going to write in total and use
    :meth:`writeframesraw` and :meth:`setnframes`.
-   Objects returned by :func:`.open` also supports the :keyword:`with` statement.
+   The :func:`.open` function may be used in a :keyword:`with` statement.  When
+   the :keyword:`with` block completes, the :meth:`~aifc.close` method is called.
 
 .. versionchanged:: 3.4
    Support for the :keyword:`with` statement was added.
diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst
--- a/Doc/library/difflib.rst
+++ b/Doc/library/difflib.rst
@@ -752,7 +752,7 @@
        # we're passing these as arguments to the diff function
        fromdate = time.ctime(os.stat(fromfile).st_mtime)
        todate = time.ctime(os.stat(tofile).st_mtime)
-       with open(fromlines) as fromf, open(tofile) as tof:
+       with open(fromfile) as fromf, open(tofile) as tof:
            fromlines, tolines = list(fromf), list(tof)
 
        if options.u:
diff --git a/Doc/library/email.iterators.rst b/Doc/library/email.iterators.rst
--- a/Doc/library/email.iterators.rst
+++ b/Doc/library/email.iterators.rst
@@ -68,7 +68,7 @@
                   text/plain
           text/plain
 
-   .. testcleanup::
+   .. testsetup::
 
       >>> somefile.close()
 
diff --git a/Doc/library/email.policy.rst b/Doc/library/email.policy.rst
--- a/Doc/library/email.policy.rst
+++ b/Doc/library/email.policy.rst
@@ -85,7 +85,7 @@
    >>> p.stdin.close()
    >>> rc = p.wait()
 
-.. testcleanup::
+.. testsetup::
 
    >>> mymsg.close()
    >>> mocker.stop()
diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst
--- a/Doc/library/enum.rst
+++ b/Doc/library/enum.rst
@@ -483,7 +483,7 @@
     ...     def __new__(cls):
     ...         value = len(cls.__members__) + 1
     ...         obj = object.__new__(cls)
-    ...         obj._value = value
+    ...         obj._value_ = value
     ...         return obj
     ...
     >>> class Color(AutoNumber):
@@ -505,19 +505,19 @@
     >>> class OrderedEnum(Enum):
     ...     def __ge__(self, other):
     ...         if self.__class__ is other.__class__:
-    ...             return self._value >= other._value
+    ...             return self.value >= other.value
     ...         return NotImplemented
     ...     def __gt__(self, other):
     ...         if self.__class__ is other.__class__:
-    ...             return self._value > other._value
+    ...             return self.value > other.value
     ...         return NotImplemented
     ...     def __le__(self, other):
     ...         if self.__class__ is other.__class__:
-    ...             return self._value <= other._value
+    ...             return self.value <= other.value
     ...         return NotImplemented
     ...     def __lt__(self, other):
     ...         if self.__class__ is other.__class__:
-    ...             return self._value < other._value
+    ...             return self.value < other.value
     ...         return NotImplemented
     ...
     >>> class Grade(OrderedEnum):
diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst
--- a/Doc/library/unittest.rst
+++ b/Doc/library/unittest.rst
@@ -974,12 +974,12 @@
       Test that a warning is triggered when *callable* is called with any
       positional or keyword arguments that are also passed to
       :meth:`assertWarns`.  The test passes if *warning* is triggered and
-      fails if it isn't.  Also, any unexpected exception is an error.
+      fails if it isn't.  Any exception is an error.
       To catch any of a group of warnings, a tuple containing the warning
       classes may be passed as *warnings*.
 
       If only the *warning* and possibly the *msg* arguments are given,
-      returns a context manager so that the code under test can be written
+      return a context manager so that the code under test can be written
       inline rather than as a function::
 
          with self.assertWarns(SomeWarning):
@@ -992,7 +992,7 @@
       :attr:`warning` attribute, and the source line which triggered the
       warnings in the :attr:`filename` and :attr:`lineno` attributes.
       This can be useful if the intention is to perform additional checks
-      on the exception raised::
+      on the warning caught::
 
          with self.assertWarns(SomeWarning) as cm:
              do_something()
diff --git a/Doc/library/wave.rst b/Doc/library/wave.rst
--- a/Doc/library/wave.rst
+++ b/Doc/library/wave.rst
@@ -39,6 +39,11 @@
    :meth:`close` method is called; it is the caller's responsibility to close
    the file object.
 
+   The :func:`.open` function may be used in a :keyword:`with` statement.  When
+   the :keyword:`with` block completes, the :meth:`Wave_read.close()
+   <wave.Wave_read.close>` or :meth:`Wave_write.close()
+   <wave.Wave_write.close()>` method is called.
+
 
 .. function:: openfp(file, mode)
 
diff --git a/Doc/tutorial/inputoutput.rst b/Doc/tutorial/inputoutput.rst
--- a/Doc/tutorial/inputoutput.rst
+++ b/Doc/tutorial/inputoutput.rst
@@ -322,9 +322,11 @@
    >>> f.write(s)
    18
 
-``f.tell()`` returns an integer giving the file object's current position in the
-file, measured in bytes from the beginning of the file.  To change the file
-object's position, use ``f.seek(offset, from_what)``.  The position is computed
+``f.tell()`` returns an integer giving the file object's current position in the file
+represented as number of bytes from the beginning of the file when in `binary mode` and
+an opaque number when in `text mode`.
+
+To change the file object's position, use ``f.seek(offset, from_what)``.  The position is computed
 from adding *offset* to a reference point; the reference point is selected by
 the *from_what* argument.  A *from_what* value of 0 measures from the beginning
 of the file, 1 uses the current file position, and 2 uses the end of the file as
@@ -345,7 +347,10 @@
 
 In text files (those opened without a ``b`` in the mode string), only seeks
 relative to the beginning of the file are allowed (the exception being seeking
-to the very file end with ``seek(0, 2)``).
+to the very file end with ``seek(0, 2)``) and the only valid *offset* values are
+those returned from the ``f.tell()``, or zero. Any other *offset* value produces
+undefined behaviour.
+
 
 When you're done with a file, call ``f.close()`` to close it and free up any
 system resources taken up by the open file.  After calling ``f.close()``,
diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst
--- a/Doc/whatsnew/3.4.rst
+++ b/Doc/whatsnew/3.4.rst
@@ -239,8 +239,11 @@
 The :meth:`~wave.getparams` method now returns a namedtuple rather than a
 plain tuple.  (Contributed by Claudiu Popa in :issue:`17487`.)
 
+:meth:`wave.open` now supports the context manager protocol.  (Contributed
+by Claudiu Popa in :issue:`17616`.)
+
 stat
----
+----
 
 The stat module is now backed by a C implementation in :mod:`_stat`. A C
 implementation is required as most of the values aren't standardized and
diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py
--- a/Lib/test/test_wave.py
+++ b/Lib/test/test_wave.py
@@ -1,7 +1,5 @@
-from test.support import TESTFN, run_unittest
-import os
+from test.support import TESTFN, unlink
 import wave
-import struct
 import unittest
 
 nchannels = 2
@@ -17,10 +15,7 @@
     def tearDown(self):
         if self.f is not None:
             self.f.close()
-        try:
-            os.remove(TESTFN)
-        except OSError:
-            pass
+        unlink(TESTFN)
 
     def test_it(self, test_rounding=False):
         self.f = wave.open(TESTFN, 'wb')
@@ -74,9 +69,23 @@
         self.assertEqual(params.comptype, self.f.getcomptype())
         self.assertEqual(params.compname, self.f.getcompname())
 
+    def test_context_manager(self):
+        self.f = wave.open(TESTFN, 'wb')
+        self.f.setnchannels(nchannels)
+        self.f.setsampwidth(sampwidth)
+        self.f.setframerate(framerate)
+        self.f.close()
 
-def test_main():
-    run_unittest(TestWave)
+        with wave.open(TESTFN) as f:
+            self.assertFalse(f.getfp().closed)
+        self.assertIs(f.getfp(), None)
+
+        with open(TESTFN, 'wb') as testfile:
+            with self.assertRaises(wave.Error):
+                with wave.open(testfile, 'wb'):
+                    pass
+            self.assertEqual(testfile.closed, False)
+
 
 if __name__ == '__main__':
-    test_main()
+    unittest.main()
diff --git a/Lib/wave.py b/Lib/wave.py
--- a/Lib/wave.py
+++ b/Lib/wave.py
@@ -167,6 +167,13 @@
 
     def __del__(self):
         self.close()
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, *args):
+        self.close()
+
     #
     # User visible methods.
     #
@@ -323,6 +330,12 @@
     def __del__(self):
         self.close()
 
+    def __enter__(self):
+        return self
+
+    def __exit__(self, *args):
+        self.close()
+
     #
     # User visible methods.
     #
diff --git a/Makefile.pre.in b/Makefile.pre.in
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -211,6 +211,12 @@
 PROFILE_TASK=	$(srcdir)/Tools/pybench/pybench.py -n 2 --with-gc --with-syscheck
 #PROFILE_TASK=	$(srcdir)/Lib/test/regrtest.py
 
+# report files for gcov / lcov coverage report
+COVERAGE_INFO=	$(abs_builddir)/coverage.info
+COVERAGE_REPORT=$(abs_builddir)/lcov-report
+COVERAGE_REPORT_OPTIONS=--no-branch-coverage --title "CPython lcov report"
+
+
 # === Definitions added by makesetup ===
 
 
@@ -463,11 +469,48 @@
 build_all_use_profile:
 	$(MAKE) all CFLAGS="$(CFLAGS) -fprofile-use -fprofile-correction"
 
+# Compile and run with gcov
+.PHONY=coverage coverage-lcov coverage-report
 coverage:
 	@echo "Building with support for coverage checking:"
-	$(MAKE) clean
+	$(MAKE) clean profile-removal
 	$(MAKE) all CFLAGS="$(CFLAGS) -O0 -pg -fprofile-arcs -ftest-coverage" LIBS="$(LIBS) -lgcov"
 
+coverage-lcov:
+	@echo "Creating Coverage HTML report with LCOV:"
+	@rm -f $(COVERAGE_INFO)
+	@rm -rf $(COVERAGE_REPORT)
+	@lcov --capture --directory $(abs_builddir) \
+	    --base-directory $(realpath $(abs_builddir)) \
+	    --path $(realpath $(abs_srcdir)) \
+	    --output-file $(COVERAGE_INFO)
+	: # remove 3rd party modules and system headers
+	@lcov --remove $(COVERAGE_INFO) \
+	    '*/Modules/_ctypes/libffi*/*' \
+	    '*/Modules/_sha3/keccak/*' \
+	    '*/Modules/_decimal/libmpdec/*' \
+	    '*/Modules/expat/*' \
+	    '*/Modules/zlib/*' \
+	    '*/Include/*' \
+	    '/usr/include/*' \
+	    '/usr/local/include/*' \
+	    --output-file $(COVERAGE_INFO)
+	@genhtml $(COVERAGE_INFO) --output-directory $(COVERAGE_REPORT) \
+	    $(COVERAGE_REPORT_OPTIONS)
+	@echo
+	@echo "lcov report at $(COVERAGE_REPORT)/index.html"
+	@echo
+
+coverage-report:
+	: # force rebuilding of parser and importlib
+	@touch $(GRAMMAR_INPUT)
+	@touch $(srcdir)/Lib/importlib/_bootstrap.py
+	: # build with coverage info
+	$(MAKE) coverage
+	: # run tests, ignore failures
+	$(TESTRUNNER) $(TESTOPTS) || true
+	: # build lcov report
+	$(MAKE) coverage-lcov
 
 # Build the interpreter
 $(BUILDPYTHON):	Modules/python.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY)
@@ -1012,7 +1055,7 @@
 		tkinter/test/test_ttk site-packages test \
 		test/capath test/data \
 		test/cjkencodings test/decimaltestdata test/xmltestdata \
-		test/subprocessdata test/sndhdrdata \
+		test/subprocessdata test/sndhdrdata test/support \
 		test/tracedmodules test/encoded_modules \
 		test/namespace_pkgs \
 		test/namespace_pkgs/both_portions \
@@ -1396,6 +1439,8 @@
 
 profile-removal:
 	find . -name '*.gc??' -exec rm -f {} ';'
+	rm -f $(COVERAGE_INFO)
+	rm -rf $(COVERAGE_REPORT)
 
 clobber: clean profile-removal
 	-rm -f $(BUILDPYTHON) $(PGEN) $(LIBRARY) $(LDLIBRARY) $(DLLLIBRARY) \
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -177,6 +177,8 @@
   initialization, so as to reclaim allocated resources (Python callbacks)
   at shutdown.  Original patch by Robin Schreiber.
 
+- Issue #17616: wave.open now supports the context manager protocol.
+
 - Issue #18599: Fix name attribute of _sha1.sha1() object. It now returns
   'SHA1' instead of 'SHA'.
 
@@ -729,6 +731,10 @@
 Build
 -----
 
+- Issue #18481: Add C coverage reporting with gcov and lcov. A new make target
+  "coverage-report" creates an instrumented Python build, runs unit tests
+  and creates a HTML. The report can be updated with "make coverage-lcov".
+
 - Issue #17845: Clarified the message printed when some module are not built.
 
 - Issue #18256: Compilation fix for recent AIX releases.  Patch by
diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c
--- a/Modules/_io/iobase.c
+++ b/Modules/_io/iobase.c
@@ -210,8 +210,10 @@
     /* If `closed` doesn't exist or can't be evaluated as bool, then the
        object is probably in an unusable state, so ignore. */
     res = PyObject_GetAttr(self, _PyIO_str_closed);
-    if (res == NULL)
+    if (res == NULL) {
         PyErr_Clear();
+        closed = -1;
+    }
     else {
         closed = PyObject_IsTrue(res);
         Py_DECREF(res);
diff --git a/Modules/_sha3/sha3module.c b/Modules/_sha3/sha3module.c
--- a/Modules/_sha3/sha3module.c
+++ b/Modules/_sha3/sha3module.c
@@ -322,7 +322,7 @@
     GET_BUFFER_VIEW_OR_ERROUT(obj, &buf);
 
     /* add new data, the function takes the length in bits not bytes */
-#ifdef WITH_THREADS
+#ifdef WITH_THREAD
     if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) {
         self->lock = PyThread_allocate_lock();
     }
@@ -464,7 +464,7 @@
     }
 
     if (data_obj) {
-#ifdef WITH_THREADS
+#ifdef WITH_THREAD
         if (buf.len >= HASHLIB_GIL_MINSIZE) {
             /* invariant: New objects can't be accessed by other code yet,
              * thus it's safe to release the GIL without locking the object.
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -2614,6 +2614,16 @@
 }
 
 static PyObject *
+test_incref_decref_API(PyObject *ob)
+{
+    PyObject *obj = PyLong_FromLong(0);
+    Py_IncRef(ob);
+    Py_DecRef(obj);
+    Py_DecRef(obj);
+    Py_RETURN_NONE;
+}
+
+static PyObject *
 test_pymem_alloc0(PyObject *self)
 {
     void *ptr;
@@ -2781,6 +2791,7 @@
     {"test_incref_doesnt_leak", (PyCFunction)test_incref_doesnt_leak,      METH_NOARGS},
     {"test_xdecref_doesnt_leak",(PyCFunction)test_xdecref_doesnt_leak,      METH_NOARGS},
     {"test_decref_doesnt_leak", (PyCFunction)test_decref_doesnt_leak,      METH_NOARGS},
+    {"test_incref_decref_API",  (PyCFunction)test_incref_decref_API,       METH_NOARGS},
     {"test_long_and_overflow", (PyCFunction)test_long_and_overflow,
      METH_NOARGS},
     {"test_long_as_double",     (PyCFunction)test_long_as_double,METH_NOARGS},

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list