diff --git a/Doc/bugs.rst b/Doc/bugs.rst index dc7d388bcc3..4db2433a1d6 100644 --- a/Doc/bugs.rst +++ b/Doc/bugs.rst @@ -23,10 +23,9 @@ In the case of documentation bugs, look at the most recent development docs at http://docs.python.org/dev to see if the bug has been fixed. If the problem you're reporting is not already in the bug tracker, go back to -the Python Bug Tracker. If you don't already have a tracker account, select the -"Register" link in the sidebar and undergo the registration procedure. -Otherwise, if you're not logged in, enter your credentials and select "Login". -It is not possible to submit a bug report anonymously. +the Python Bug Tracker and log in. If you don't already have a tracker account, +select the "Register" link or, if you use OpenID, one of the OpenID provider +logos in the sidebar. It is not possible to submit a bug report anonymously. Being now logged in, you can submit a bug. Select the "Create New" link in the sidebar to open the bug reporting form. @@ -43,7 +42,8 @@ were using (including version information as appropriate). Each bug report will be assigned to a developer who will determine what needs to be done to correct the problem. You will receive an update each time action is -taken on the bug. +taken on the bug. See http://www.python.org/dev/workflow/ for a detailed +description of the issue workflow. .. seealso:: diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 7c5902274d2..19520320259 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -350,9 +350,10 @@ A high-level explanation of the context management protocol is: * The code in *BLOCK* is executed. -* If *BLOCK* raises an exception, the :meth:`__exit__(type, value, traceback)` - is called with the exception details, the same values returned by - :func:`sys.exc_info`. The method's return value controls whether the exception +* If *BLOCK* raises an exception, the context manager's :meth:`__exit__` method + is called with three arguments, the exception details (``type, value, traceback``, + the same values returned by :func:`sys.exc_info`, which can also be ``None`` + if no exception occurred). The method's return value controls whether an exception is re-raised: any false value re-raises the exception, and ``True`` will result in suppressing it. You'll only rarely want to suppress the exception, because if you do the author of the code containing the ':keyword:`with`' statement will @@ -463,7 +464,7 @@ could be written as:: with db_transaction(db) as cursor: ... -The :mod:`contextlib` module also has a :func:`nested(mgr1, mgr2, ...)` function +The :mod:`contextlib` module also has a ``nested(mgr1, mgr2, ...)`` function that combines a number of context managers so you don't need to write nested ':keyword:`with`' statements. In this example, the single ':keyword:`with`' statement both starts a database transaction and acquires a thread lock:: @@ -472,8 +473,9 @@ statement both starts a database transaction and acquires a thread lock:: with nested (db_transaction(db), lock) as (cursor, locked): ... -Finally, the :func:`closing(object)` function returns *object* so that it can be -bound to a variable, and calls ``object.close`` at the end of the block. :: +Finally, the :func:`closing` function returns its argument so that it can be +bound to a variable, and calls the argument's ``.close()`` method at the end +of the block. :: import urllib, sys from contextlib import closing diff --git a/Lib/test/test_fnmatch.py b/Lib/test/test_fnmatch.py index 2b510995796..6d2f9ada561 100644 --- a/Lib/test/test_fnmatch.py +++ b/Lib/test/test_fnmatch.py @@ -7,13 +7,13 @@ from fnmatch import fnmatch, fnmatchcase class FnmatchTestCase(unittest.TestCase): - def check_match(self, filename, pattern, should_match=1): + def check_match(self, filename, pattern, should_match=1, fn=fnmatch): if should_match: - self.assertTrue(fnmatch(filename, pattern), + self.assertTrue(fn(filename, pattern), "expected %r to match pattern %r" % (filename, pattern)) else: - self.assertTrue(not fnmatch(filename, pattern), + self.assertTrue(not fn(filename, pattern), "expected %r not to match pattern %r" % (filename, pattern)) @@ -52,8 +52,8 @@ class FnmatchTestCase(unittest.TestCase): def test_fnmatchcase(self): check = self.check_match - check('AbC', 'abc', 0) - check('abc', 'AbC', 0) + check('AbC', 'abc', 0, fnmatchcase) + check('abc', 'AbC', 0, fnmatchcase) def test_bytes(self): self.check_match(b'test', b'te*') diff --git a/Lib/test/test_strftime.py b/Lib/test/test_strftime.py index 41144b720be..14057eb34ac 100644 --- a/Lib/test/test_strftime.py +++ b/Lib/test/test_strftime.py @@ -116,16 +116,15 @@ class StrftimeTest(unittest.TestCase): try: result = time.strftime(e[0], now) except ValueError as error: - print("Standard '%s' format gaver error:" % (e[0], error)) - continue + self.fail("strftime '%s' format gave error: %s" % (e[0], error)) if re.match(escapestr(e[1], self.ampm), result): continue if not result or result[0] == '%': - print("Does not support standard '%s' format (%s)" % \ - (e[0], e[2])) + self.fail("strftime does not support standard '%s' format (%s)" + % (e[0], e[2])) else: - print("Conflict for %s (%s):" % (e[0], e[2])) - print(" Expected %s, but got %s" % (e[1], result)) + self.fail("Conflict for %s (%s): expected %s, but got %s" + % (e[0], e[2], e[1], result)) def strftest2(self, now): nowsecs = str(int(now))[:-1] diff --git a/Misc/NEWS b/Misc/NEWS index 8651d1fb63d..b8c098c353e 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -781,6 +781,9 @@ Library Extension Modules ----------------- +- Issue #6544: fix a reference leak in the kqueue implementation's error + handling. + - Stop providing crtassem.h symbols when compiling with Visual Studio 2010, as msvcr100.dll is not a platform assembly anymore. diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c index 9f1b96825e8..c13bab91fc3 100644 --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -1241,6 +1241,7 @@ static struct PyMemberDef kqueue_event_members[] = { #undef KQ_OFF static PyObject * + kqueue_event_repr(kqueue_event_Object *s) { char buf[1024]; @@ -1526,19 +1527,6 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args) return NULL; } - if (ch != NULL && ch != Py_None) { - it = PyObject_GetIter(ch); - if (it == NULL) { - PyErr_SetString(PyExc_TypeError, - "changelist is not iterable"); - return NULL; - } - nchanges = PyObject_Size(ch); - if (nchanges < 0) { - return NULL; - } - } - if (otimeout == Py_None || otimeout == NULL) { ptimeoutspec = NULL; } @@ -1574,11 +1562,22 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args) return NULL; } - if (nchanges) { + if (ch != NULL && ch != Py_None) { + it = PyObject_GetIter(ch); + if (it == NULL) { + PyErr_SetString(PyExc_TypeError, + "changelist is not iterable"); + return NULL; + } + nchanges = PyObject_Size(ch); + if (nchanges < 0) { + goto error; + } + chl = PyMem_New(struct kevent, nchanges); if (chl == NULL) { PyErr_NoMemory(); - return NULL; + goto error; } i = 0; while ((ei = PyIter_Next(it)) != NULL) { @@ -1601,7 +1600,7 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args) evl = PyMem_New(struct kevent, nevents); if (evl == NULL) { PyErr_NoMemory(); - return NULL; + goto error; } }