diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2013-07-31 21:54:18 +0200 |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2013-07-31 21:54:18 +0200 |
commit | c27cd71cd71e5b3f464f6994e2a73f201eb430ca (patch) | |
tree | b973bb782096772fc8a38a0c3bd534acc867c10a | |
parent | 5c30a75722f1fb42f4e49dcc5dd30d90d7717086 (diff) | |
parent | c91d5eea106d191e931f953bdbdb1db25e051767 (diff) | |
download | cpython-git-c27cd71cd71e5b3f464f6994e2a73f201eb430ca.tar.gz |
Merge
-rw-r--r-- | .hgignore | 5 | ||||
-rw-r--r-- | Doc/library/aifc.rst | 3 | ||||
-rw-r--r-- | Doc/library/difflib.rst | 2 | ||||
-rw-r--r-- | Doc/library/email.iterators.rst | 2 | ||||
-rw-r--r-- | Doc/library/email.policy.rst | 2 | ||||
-rw-r--r-- | Doc/library/enum.rst | 10 | ||||
-rw-r--r-- | Doc/library/unittest.rst | 6 | ||||
-rw-r--r-- | Doc/library/wave.rst | 5 | ||||
-rw-r--r-- | Doc/tutorial/inputoutput.rst | 13 | ||||
-rw-r--r-- | Doc/whatsnew/3.4.rst | 5 | ||||
-rw-r--r-- | Lib/test/test_wave.py | 29 | ||||
-rw-r--r-- | Lib/wave.py | 13 | ||||
-rw-r--r-- | Makefile.pre.in | 49 | ||||
-rw-r--r-- | Misc/NEWS | 6 | ||||
-rw-r--r-- | Modules/_io/iobase.c | 4 | ||||
-rw-r--r-- | Modules/_sha3/sha3module.c | 4 | ||||
-rw-r--r-- | Modules/_testcapimodule.c | 11 |
17 files changed, 137 insertions, 32 deletions
@@ -36,6 +36,7 @@ Modules/Setup.local Modules/config.c Modules/ld_so_aix$ Parser/pgen$ +^lcov-report/ ^core ^python-gdb.py ^python.exe-gdb.py @@ -91,3 +92,7 @@ Modules/_testembed .coverage coverage/ htmlcov/ +*.gcda +*.gcno +*.gcov +coverage.info diff --git a/Doc/library/aifc.rst b/Doc/library/aifc.rst index c1cd215c3f..44a0a24ff5 100644 --- a/Doc/library/aifc.rst +++ b/Doc/library/aifc.rst @@ -51,7 +51,8 @@ Module :mod:`aifc` defines the following function: 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 index 836e240b83..ad1466efaa 100644 --- a/Doc/library/difflib.rst +++ b/Doc/library/difflib.rst @@ -752,7 +752,7 @@ It is also contained in the Python source distribution, as # 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 index 6c7200f98a..7882718695 100644 --- a/Doc/library/email.iterators.rst +++ b/Doc/library/email.iterators.rst @@ -68,7 +68,7 @@ The following function has been added as a useful debugging tool. It should text/plain text/plain - .. testcleanup:: + .. testsetup:: >>> somefile.close() diff --git a/Doc/library/email.policy.rst b/Doc/library/email.policy.rst index d85054ac83..54ebb1cf11 100644 --- a/Doc/library/email.policy.rst +++ b/Doc/library/email.policy.rst @@ -85,7 +85,7 @@ file on disk and pass it to the system ``sendmail`` program on a Unix system: >>> p.stdin.close() >>> rc = p.wait() -.. testcleanup:: +.. testsetup:: >>> mymsg.close() >>> mocker.stop() diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index 1e464d7361..686470534d 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -483,7 +483,7 @@ Avoids having to specify the value for each enumeration member:: ... 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 @@ enumerations):: >>> 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 index a5c4783682..6c9f2f1868 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -974,12 +974,12 @@ Test cases 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 @@ Test cases :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 index 2e64d00305..c52af89774 100644 --- a/Doc/library/wave.rst +++ b/Doc/library/wave.rst @@ -39,6 +39,11 @@ The :mod:`wave` module defines the following function and exception: :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 index 744abab988..7daf89b79b 100644 --- a/Doc/tutorial/inputoutput.rst +++ b/Doc/tutorial/inputoutput.rst @@ -322,9 +322,11 @@ first:: >>> 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 @@ beginning of the file as the reference point. :: 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 index 17cec3f2ad..2575170f44 100644 --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -239,8 +239,11 @@ wave 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 index 581d9739d5..e9ee15ca9a 100644 --- 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 @@ class TestWave(unittest.TestCase): 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 @@ class TestWave(unittest.TestCase): 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() + + 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) -def test_main(): - run_unittest(TestWave) if __name__ == '__main__': - test_main() + unittest.main() diff --git a/Lib/wave.py b/Lib/wave.py index ea410c12d7..695a4be838 100644 --- a/Lib/wave.py +++ b/Lib/wave.py @@ -167,6 +167,13 @@ class Wave_read: def __del__(self): self.close() + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + # # User visible methods. # @@ -323,6 +330,12 @@ class Wave_write: 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 index 6e0492235c..ad4eb30824 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -211,6 +211,12 @@ HOST_GNU_TYPE= @host@ 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 @@ run_profile_task: 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 @@ LIBSUBDIRS= tkinter tkinter/test tkinter/test/test_tkinter \ 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 @@ clean: pycremoval 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) \ @@ -177,6 +177,8 @@ Library 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 @@ IDLE 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 index a4f2c0e917..ae188dd7fe 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -210,8 +210,10 @@ iobase_finalize(PyObject *self) /* 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 index 32cd85a1ef..4e6352b7ba 100644 --- a/Modules/_sha3/sha3module.c +++ b/Modules/_sha3/sha3module.c @@ -322,7 +322,7 @@ SHA3_update(SHA3object *self, PyObject *args) 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 @@ SHA3_factory(PyObject *args, PyObject *kwdict, const char *fmt, } 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 index 6527a53362..1ed56873ce 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2614,6 +2614,16 @@ test_decref_doesnt_leak(PyObject *ob) } 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 @@ static PyMethodDef TestMethods[] = { {"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}, |