diff options
-rw-r--r-- | Doc/library/cookie.rst | 10 | ||||
-rw-r--r-- | Doc/library/webbrowser.rst | 9 | ||||
-rw-r--r-- | Lib/HTMLParser.py | 6 | ||||
-rw-r--r-- | Lib/test/test_htmlparser.py | 10 | ||||
-rw-r--r-- | Lib/test/test_sys_settrace.py | 11 | ||||
-rw-r--r-- | Lib/test/test_threading.py | 29 | ||||
-rw-r--r-- | Lib/threading.py | 4 | ||||
-rw-r--r-- | Misc/NEWS | 8 | ||||
-rw-r--r-- | Objects/frameobject.c | 6 | ||||
-rw-r--r-- | Python/import.c | 3 |
10 files changed, 81 insertions, 15 deletions
diff --git a/Doc/library/cookie.rst b/Doc/library/cookie.rst index 480dffa66e..52c897579d 100644 --- a/Doc/library/cookie.rst +++ b/Doc/library/cookie.rst @@ -22,8 +22,14 @@ cookie value. The module formerly strictly applied the parsing rules described in the :rfc:`2109` and :rfc:`2068` specifications. It has since been discovered that -MSIE 3.0x doesn't follow the character rules outlined in those specs. As a -result, the parsing rules used are a bit less strict. +MSIE 3.0x doesn't follow the character rules outlined in those specs and also +many current day browsers and servers have relaxed parsing rules when comes to +Cookie handling. As a result, the parsing rules used are a bit less strict. + +The character set, :data:`string.ascii_letters`, :data:`string.digits` and +``!#$%&'*+-.^_`|~`` denote the set of valid characters allowed by this module +in Cookie name (as :attr:`~Morsel.key`). + .. note:: diff --git a/Doc/library/webbrowser.rst b/Doc/library/webbrowser.rst index 05de5894f4..b978777bd4 100644 --- a/Doc/library/webbrowser.rst +++ b/Doc/library/webbrowser.rst @@ -138,11 +138,9 @@ for the controller classes, all defined in this module. +-----------------------+-----------------------------------------+-------+ | ``'windows-default'`` | :class:`WindowsDefault` | \(2) | +-----------------------+-----------------------------------------+-------+ -| ``'internet-config'`` | :class:`InternetConfig` | \(3) | +| ``'macosx'`` | :class:`MacOSX('default')` | \(3) | +-----------------------+-----------------------------------------+-------+ -| ``'macosx'`` | :class:`MacOSX('default')` | \(4) | -+-----------------------+-----------------------------------------+-------+ -| ``'safari'`` | :class:`MacOSX('safari')` | \(4) | +| ``'safari'`` | :class:`MacOSX('safari')` | \(3) | +-----------------------+-----------------------------------------+-------+ Notes: @@ -158,9 +156,6 @@ Notes: Only on Windows platforms. (3) - Only on Mac OS platforms; requires the standard MacPython :mod:`ic` module. - -(4) Only on Mac OS X platform. Here are some simple examples:: diff --git a/Lib/HTMLParser.py b/Lib/HTMLParser.py index d4e14d4387..b336a4c31d 100644 --- a/Lib/HTMLParser.py +++ b/Lib/HTMLParser.py @@ -22,13 +22,13 @@ charref = re.compile('&#(?:[0-9]+|[xX][0-9a-fA-F]+)[^0-9a-fA-F]') starttagopen = re.compile('<[a-zA-Z]') piclose = re.compile('>') commentclose = re.compile(r'--\s*>') -tagfind = re.compile('[a-zA-Z][-.a-zA-Z0-9:_]*') +tagfind = re.compile('([a-zA-Z][-.a-zA-Z0-9:_]*)(?:\s|/(?!>))*') # see http://www.w3.org/TR/html5/tokenization.html#tag-open-state # and http://www.w3.org/TR/html5/tokenization.html#tag-name-state tagfind_tolerant = re.compile('[a-zA-Z][^\t\n\r\f />\x00]*') attrfind = re.compile( - r'[\s/]*((?<=[\'"\s/])[^\s/>][^\s/=>]*)(\s*=+\s*' + r'((?<=[\'"\s/])[^\s/>][^\s/=>]*)(\s*=+\s*' r'(\'[^\']*\'|"[^"]*"|(?![\'"])[^>\s]*))?(?:\s|/(?!>))*') locatestarttagend = re.compile(r""" @@ -289,7 +289,7 @@ class HTMLParser(markupbase.ParserBase): match = tagfind.match(rawdata, i+1) assert match, 'unexpected call to parse_starttag()' k = match.end() - self.lasttag = tag = rawdata[i+1:k].lower() + self.lasttag = tag = match.group(1).lower() while k < endpos: m = attrfind.match(rawdata, k) diff --git a/Lib/test/test_htmlparser.py b/Lib/test/test_htmlparser.py index 41f43408d8..8cc461f1ee 100644 --- a/Lib/test/test_htmlparser.py +++ b/Lib/test/test_htmlparser.py @@ -260,6 +260,16 @@ text ('starttag', 'a', [('foo', None), ('=', None), ('bar', None)]) ] self._run_check(html, expected) + #see issue #14538 + html = ('<meta><meta / ><meta // ><meta / / >' + '<meta/><meta /><meta //><meta//>') + expected = [ + ('starttag', 'meta', []), ('starttag', 'meta', []), + ('starttag', 'meta', []), ('starttag', 'meta', []), + ('startendtag', 'meta', []), ('startendtag', 'meta', []), + ('startendtag', 'meta', []), ('startendtag', 'meta', []), + ] + self._run_check(html, expected) def test_declaration_junk_chars(self): self._run_check("<!DOCTYPE foo $ >", [('decl', 'DOCTYPE foo $ ')]) diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index 1f77f9b16b..57a7839189 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -670,6 +670,14 @@ def no_jump_to_non_integers(output): no_jump_to_non_integers.jump = (2, "Spam") no_jump_to_non_integers.output = [True] +def jump_across_with(output): + with open(test_support.TESTFN, "wb") as fp: + pass + with open(test_support.TESTFN, "wb") as fp: + pass +jump_across_with.jump = (1, 3) +jump_across_with.output = [] + # This verifies that you can't set f_lineno via _getframe or similar # trickery. def no_jump_without_trace_function(): @@ -739,6 +747,9 @@ class JumpTestCase(unittest.TestCase): self.run_test(no_jump_to_non_integers) def test_19_no_jump_without_trace_function(self): no_jump_without_trace_function() + def test_jump_across_with(self): + self.addCleanup(test_support.unlink, test_support.TESTFN) + self.run_test(jump_across_with) def test_20_large_function(self): d = {} diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 1a02ef2e31..ef04cd360a 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -2,6 +2,8 @@ import test.test_support from test.test_support import verbose +from test.script_helper import assert_python_ok + import random import re import sys @@ -414,6 +416,33 @@ class ThreadTests(BaseTestCase): msg=('%d references still around' % sys.getrefcount(weak_raising_cyclic_object()))) + @unittest.skipUnless(hasattr(os, 'fork'), 'test needs fork()') + def test_dummy_thread_after_fork(self): + # Issue #14308: a dummy thread in the active list doesn't mess up + # the after-fork mechanism. + code = """if 1: + import thread, threading, os, time + + def background_thread(evt): + # Creates and registers the _DummyThread instance + threading.current_thread() + evt.set() + time.sleep(10) + + evt = threading.Event() + thread.start_new_thread(background_thread, (evt,)) + evt.wait() + assert threading.active_count() == 2, threading.active_count() + if os.fork() == 0: + assert threading.active_count() == 1, threading.active_count() + os._exit(0) + else: + os.wait() + """ + _, out, err = assert_python_ok("-c", code) + self.assertEqual(out, '') + self.assertEqual(err, '') + class ThreadJoinOnShutdown(BaseTestCase): diff --git a/Lib/threading.py b/Lib/threading.py index ff32dfb41c..22908550e0 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -605,6 +605,10 @@ class Thread(_Verbose): pass def __stop(self): + # DummyThreads delete self.__block, but they have no waiters to + # notify anyway (join() is forbidden on them). + if not hasattr(self, '_Thread__block'): + return self.__block.acquire() self.__stopped = True self.__block.notify_all() @@ -9,6 +9,8 @@ What's New in Python 2.7.4 Core and Builtins ----------------- +- Issue #14612: Fix jumping around with blocks by setting f_lineno. + - Issue #13889: Check and (if necessary) set FPU control word before calling any of the dtoa.c string <-> float conversion functions, on MSVC builds of Python. This fixes issues when embedding Python in a Delphi app. @@ -48,6 +50,12 @@ Core and Builtins Library ------- +- Issue #14308: Fix an exception when a "dummy" thread is in the threading + module's active list after a fork(). + +- Issue #14538: HTMLParser can now parse correctly start tags that contain + a bare '/'. + - Issue #14452: SysLogHandler no longer inserts a UTF-8 BOM into the message. - Issue #13496: Fix potential overflow in bisect.bisect algorithm when applied diff --git a/Objects/frameobject.c b/Objects/frameobject.c index a3476cfff1..f9e4a0ead6 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -214,6 +214,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno) case SETUP_LOOP: case SETUP_EXCEPT: case SETUP_FINALLY: + case SETUP_WITH: blockstack[blockstack_top++] = addr; in_finally[blockstack_top-1] = 0; break; @@ -221,7 +222,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno) case POP_BLOCK: assert(blockstack_top > 0); setup_op = code[blockstack[blockstack_top-1]]; - if (setup_op == SETUP_FINALLY) { + if (setup_op == SETUP_FINALLY || setup_op == SETUP_WITH) { in_finally[blockstack_top-1] = 1; } else { @@ -236,7 +237,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno) * be seeing such an END_FINALLY.) */ if (blockstack_top > 0) { setup_op = code[blockstack[blockstack_top-1]]; - if (setup_op == SETUP_FINALLY) { + if (setup_op == SETUP_FINALLY || setup_op == SETUP_WITH) { blockstack_top--; } } @@ -298,6 +299,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno) case SETUP_LOOP: case SETUP_EXCEPT: case SETUP_FINALLY: + case SETUP_WITH: delta_iblock++; break; diff --git a/Python/import.c b/Python/import.c index 4d8a610c3d..108a1e1b07 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1267,7 +1267,8 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, } name = PyMem_MALLOC(MAXPATHLEN+1); if (name == NULL) { - return PyErr_NoMemory(); + PyErr_NoMemory(); + return NULL; } strcpy(name, subname); |