This commit is contained in:
Antoine Pitrou 2013-07-31 21:54:18 +02:00
commit c27cd71cd7
17 changed files with 137 additions and 32 deletions

View File

@ -36,6 +36,7 @@ Modules/Setup.local
Modules/config.c Modules/config.c
Modules/ld_so_aix$ Modules/ld_so_aix$
Parser/pgen$ Parser/pgen$
^lcov-report/
^core ^core
^python-gdb.py ^python-gdb.py
^python.exe-gdb.py ^python.exe-gdb.py
@ -91,3 +92,7 @@ Modules/_testembed
.coverage .coverage
coverage/ coverage/
htmlcov/ htmlcov/
*.gcda
*.gcno
*.gcov
coverage.info

View File

@ -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 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 time how many samples you are going to write in total and use
:meth:`writeframesraw` and :meth:`setnframes`. :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 .. versionchanged:: 3.4
Support for the :keyword:`with` statement was added. Support for the :keyword:`with` statement was added.

View File

@ -752,7 +752,7 @@ It is also contained in the Python source distribution, as
# we're passing these as arguments to the diff function # we're passing these as arguments to the diff function
fromdate = time.ctime(os.stat(fromfile).st_mtime) fromdate = time.ctime(os.stat(fromfile).st_mtime)
todate = time.ctime(os.stat(tofile).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) fromlines, tolines = list(fromf), list(tof)
if options.u: if options.u:

View File

@ -68,7 +68,7 @@ The following function has been added as a useful debugging tool. It should
text/plain text/plain
text/plain text/plain
.. testcleanup:: .. testsetup::
>>> somefile.close() >>> somefile.close()

View File

@ -85,7 +85,7 @@ file on disk and pass it to the system ``sendmail`` program on a Unix system:
>>> p.stdin.close() >>> p.stdin.close()
>>> rc = p.wait() >>> rc = p.wait()
.. testcleanup:: .. testsetup::
>>> mymsg.close() >>> mymsg.close()
>>> mocker.stop() >>> mocker.stop()

View File

@ -483,7 +483,7 @@ Avoids having to specify the value for each enumeration member::
... def __new__(cls): ... def __new__(cls):
... value = len(cls.__members__) + 1 ... value = len(cls.__members__) + 1
... obj = object.__new__(cls) ... obj = object.__new__(cls)
... obj._value = value ... obj._value_ = value
... return obj ... return obj
... ...
>>> class Color(AutoNumber): >>> class Color(AutoNumber):
@ -505,19 +505,19 @@ enumerations)::
>>> class OrderedEnum(Enum): >>> class OrderedEnum(Enum):
... def __ge__(self, other): ... def __ge__(self, other):
... if self.__class__ is other.__class__: ... if self.__class__ is other.__class__:
... return self._value >= other._value ... return self.value >= other.value
... return NotImplemented ... return NotImplemented
... def __gt__(self, other): ... def __gt__(self, other):
... if self.__class__ is other.__class__: ... if self.__class__ is other.__class__:
... return self._value > other._value ... return self.value > other.value
... return NotImplemented ... return NotImplemented
... def __le__(self, other): ... def __le__(self, other):
... if self.__class__ is other.__class__: ... if self.__class__ is other.__class__:
... return self._value <= other._value ... return self.value <= other.value
... return NotImplemented ... return NotImplemented
... def __lt__(self, other): ... def __lt__(self, other):
... if self.__class__ is other.__class__: ... if self.__class__ is other.__class__:
... return self._value < other._value ... return self.value < other.value
... return NotImplemented ... return NotImplemented
... ...
>>> class Grade(OrderedEnum): >>> class Grade(OrderedEnum):

View File

@ -974,12 +974,12 @@ Test cases
Test that a warning is triggered when *callable* is called with any Test that a warning is triggered when *callable* is called with any
positional or keyword arguments that are also passed to positional or keyword arguments that are also passed to
:meth:`assertWarns`. The test passes if *warning* is triggered and :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 To catch any of a group of warnings, a tuple containing the warning
classes may be passed as *warnings*. classes may be passed as *warnings*.
If only the *warning* and possibly the *msg* arguments are given, 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:: inline rather than as a function::
with self.assertWarns(SomeWarning): with self.assertWarns(SomeWarning):
@ -992,7 +992,7 @@ Test cases
:attr:`warning` attribute, and the source line which triggered the :attr:`warning` attribute, and the source line which triggered the
warnings in the :attr:`filename` and :attr:`lineno` attributes. warnings in the :attr:`filename` and :attr:`lineno` attributes.
This can be useful if the intention is to perform additional checks 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: with self.assertWarns(SomeWarning) as cm:
do_something() do_something()

View File

@ -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 :meth:`close` method is called; it is the caller's responsibility to close
the file object. 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) .. function:: openfp(file, mode)

View File

@ -322,9 +322,11 @@ first::
>>> f.write(s) >>> f.write(s)
18 18
``f.tell()`` returns an integer giving the file object's current position in the ``f.tell()`` returns an integer giving the file object's current position in the file
file, measured in bytes from the beginning of the file. To change the file represented as number of bytes from the beginning of the file when in `binary mode` and
object's position, use ``f.seek(offset, from_what)``. The position is computed 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 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 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 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 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 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 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()``, system resources taken up by the open file. After calling ``f.close()``,

View File

@ -239,8 +239,11 @@ wave
The :meth:`~wave.getparams` method now returns a namedtuple rather than a The :meth:`~wave.getparams` method now returns a namedtuple rather than a
plain tuple. (Contributed by Claudiu Popa in :issue:`17487`.) 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 stat
--- ----
The stat module is now backed by a C implementation in :mod:`_stat`. A C 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 implementation is required as most of the values aren't standardized and

View File

@ -1,7 +1,5 @@
from test.support import TESTFN, run_unittest from test.support import TESTFN, unlink
import os
import wave import wave
import struct
import unittest import unittest
nchannels = 2 nchannels = 2
@ -17,10 +15,7 @@ class TestWave(unittest.TestCase):
def tearDown(self): def tearDown(self):
if self.f is not None: if self.f is not None:
self.f.close() self.f.close()
try: unlink(TESTFN)
os.remove(TESTFN)
except OSError:
pass
def test_it(self, test_rounding=False): def test_it(self, test_rounding=False):
self.f = wave.open(TESTFN, 'wb') self.f = wave.open(TESTFN, 'wb')
@ -74,9 +69,23 @@ class TestWave(unittest.TestCase):
self.assertEqual(params.comptype, self.f.getcomptype()) self.assertEqual(params.comptype, self.f.getcomptype())
self.assertEqual(params.compname, self.f.getcompname()) 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__': if __name__ == '__main__':
test_main() unittest.main()

View File

@ -167,6 +167,13 @@ class Wave_read:
def __del__(self): def __del__(self):
self.close() self.close()
def __enter__(self):
return self
def __exit__(self, *args):
self.close()
# #
# User visible methods. # User visible methods.
# #
@ -323,6 +330,12 @@ class Wave_write:
def __del__(self): def __del__(self):
self.close() self.close()
def __enter__(self):
return self
def __exit__(self, *args):
self.close()
# #
# User visible methods. # User visible methods.
# #

View File

@ -211,6 +211,12 @@ HOST_GNU_TYPE= @host@
PROFILE_TASK= $(srcdir)/Tools/pybench/pybench.py -n 2 --with-gc --with-syscheck PROFILE_TASK= $(srcdir)/Tools/pybench/pybench.py -n 2 --with-gc --with-syscheck
#PROFILE_TASK= $(srcdir)/Lib/test/regrtest.py #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 === # === Definitions added by makesetup ===
@ -463,11 +469,48 @@ run_profile_task:
build_all_use_profile: build_all_use_profile:
$(MAKE) all CFLAGS="$(CFLAGS) -fprofile-use -fprofile-correction" $(MAKE) all CFLAGS="$(CFLAGS) -fprofile-use -fprofile-correction"
# Compile and run with gcov
.PHONY=coverage coverage-lcov coverage-report
coverage: coverage:
@echo "Building with support for coverage checking:" @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" $(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 # Build the interpreter
$(BUILDPYTHON): Modules/python.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY) $(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 \ tkinter/test/test_ttk site-packages test \
test/capath test/data \ test/capath test/data \
test/cjkencodings test/decimaltestdata test/xmltestdata \ test/cjkencodings test/decimaltestdata test/xmltestdata \
test/subprocessdata test/sndhdrdata \ test/subprocessdata test/sndhdrdata test/support \
test/tracedmodules test/encoded_modules \ test/tracedmodules test/encoded_modules \
test/namespace_pkgs \ test/namespace_pkgs \
test/namespace_pkgs/both_portions \ test/namespace_pkgs/both_portions \
@ -1396,6 +1439,8 @@ clean: pycremoval
profile-removal: profile-removal:
find . -name '*.gc??' -exec rm -f {} ';' find . -name '*.gc??' -exec rm -f {} ';'
rm -f $(COVERAGE_INFO)
rm -rf $(COVERAGE_REPORT)
clobber: clean profile-removal clobber: clean profile-removal
-rm -f $(BUILDPYTHON) $(PGEN) $(LIBRARY) $(LDLIBRARY) $(DLLLIBRARY) \ -rm -f $(BUILDPYTHON) $(PGEN) $(LIBRARY) $(LDLIBRARY) $(DLLLIBRARY) \

View File

@ -177,6 +177,8 @@ Library
initialization, so as to reclaim allocated resources (Python callbacks) initialization, so as to reclaim allocated resources (Python callbacks)
at shutdown. Original patch by Robin Schreiber. 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 - Issue #18599: Fix name attribute of _sha1.sha1() object. It now returns
'SHA1' instead of 'SHA'. 'SHA1' instead of 'SHA'.
@ -729,6 +731,10 @@ IDLE
Build 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 #17845: Clarified the message printed when some module are not built.
- Issue #18256: Compilation fix for recent AIX releases. Patch by - Issue #18256: Compilation fix for recent AIX releases. Patch by

View File

@ -210,8 +210,10 @@ iobase_finalize(PyObject *self)
/* If `closed` doesn't exist or can't be evaluated as bool, then the /* If `closed` doesn't exist or can't be evaluated as bool, then the
object is probably in an unusable state, so ignore. */ object is probably in an unusable state, so ignore. */
res = PyObject_GetAttr(self, _PyIO_str_closed); res = PyObject_GetAttr(self, _PyIO_str_closed);
if (res == NULL) if (res == NULL) {
PyErr_Clear(); PyErr_Clear();
closed = -1;
}
else { else {
closed = PyObject_IsTrue(res); closed = PyObject_IsTrue(res);
Py_DECREF(res); Py_DECREF(res);

View File

@ -322,7 +322,7 @@ SHA3_update(SHA3object *self, PyObject *args)
GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); GET_BUFFER_VIEW_OR_ERROUT(obj, &buf);
/* add new data, the function takes the length in bits not bytes */ /* 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) { if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) {
self->lock = PyThread_allocate_lock(); self->lock = PyThread_allocate_lock();
} }
@ -464,7 +464,7 @@ SHA3_factory(PyObject *args, PyObject *kwdict, const char *fmt,
} }
if (data_obj) { if (data_obj) {
#ifdef WITH_THREADS #ifdef WITH_THREAD
if (buf.len >= HASHLIB_GIL_MINSIZE) { if (buf.len >= HASHLIB_GIL_MINSIZE) {
/* invariant: New objects can't be accessed by other code yet, /* invariant: New objects can't be accessed by other code yet,
* thus it's safe to release the GIL without locking the object. * thus it's safe to release the GIL without locking the object.

View File

@ -2613,6 +2613,16 @@ test_decref_doesnt_leak(PyObject *ob)
Py_RETURN_NONE; Py_RETURN_NONE;
} }
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 * static PyObject *
test_pymem_alloc0(PyObject *self) test_pymem_alloc0(PyObject *self)
{ {
@ -2781,6 +2791,7 @@ static PyMethodDef TestMethods[] = {
{"test_incref_doesnt_leak", (PyCFunction)test_incref_doesnt_leak, METH_NOARGS}, {"test_incref_doesnt_leak", (PyCFunction)test_incref_doesnt_leak, METH_NOARGS},
{"test_xdecref_doesnt_leak",(PyCFunction)test_xdecref_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_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, {"test_long_and_overflow", (PyCFunction)test_long_and_overflow,
METH_NOARGS}, METH_NOARGS},
{"test_long_as_double", (PyCFunction)test_long_as_double,METH_NOARGS}, {"test_long_as_double", (PyCFunction)test_long_as_double,METH_NOARGS},