diff options
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/cgitb.py | 11 | ||||
-rw-r--r-- | Lib/idlelib/NEWS.txt | 3 | ||||
-rw-r--r-- | Lib/idlelib/configDialog.py | 7 | ||||
-rw-r--r-- | Lib/idlelib/help.txt | 15 | ||||
-rwxr-xr-x | Lib/test/regrtest.py | 4 | ||||
-rw-r--r-- | Lib/test/test_bz2.py | 40 | ||||
-rw-r--r-- | Lib/test/test_codecs.py | 2 | ||||
-rw-r--r-- | Lib/test/test_gdb.py | 84 | ||||
-rw-r--r-- | Lib/test/test_import.py | 60 | ||||
-rw-r--r-- | Lib/test/test_unicode.py | 27 | ||||
-rw-r--r-- | Lib/test/test_urllib.py | 35 | ||||
-rw-r--r-- | Lib/test/test_urllib2net.py | 4 | ||||
-rw-r--r-- | Lib/test/test_wsgiref.py | 106 | ||||
-rw-r--r-- | Lib/test/testbz2_bigmem.bz2 | bin | 0 -> 3023 bytes | |||
-rw-r--r-- | Lib/urllib/request.py | 39 | ||||
-rw-r--r-- | Lib/wsgiref/handlers.py | 12 |
16 files changed, 274 insertions, 175 deletions
diff --git a/Lib/cgitb.py b/Lib/cgitb.py index 7b52c8e..6da40e8 100644 --- a/Lib/cgitb.py +++ b/Lib/cgitb.py @@ -293,14 +293,19 @@ class Hook: if self.logdir is not None: suffix = ['.txt', '.html'][self.format=="html"] (fd, path) = tempfile.mkstemp(suffix=suffix, dir=self.logdir) + try: file = os.fdopen(fd, 'w') file.write(doc) file.close() - msg = '<p> %s contains the description of this error.' % path + msg = '%s contains the description of this error.' % path except: - msg = '<p> Tried to save traceback to %s, but failed.' % path - self.file.write(msg + '\n') + msg = 'Tried to save traceback to %s, but failed.' % path + + if self.format == 'html': + self.file.write('<p>%s</p>\n' % msg) + else: + self.file.write(msg + '\n') try: self.file.flush() except: pass diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 3160c74..f234b64 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -21,6 +21,9 @@ What's New in IDLE 3.2.4? - Issue #14018: Update checks for unstable system Tcl/Tk versions on OS X to include versions shipped with OS X 10.7 and 10.8 in addition to 10.6. +- Issue #15853: Prevent IDLE crash on OS X when opening Preferences menu + with certain versions of Tk 8.5. Initial patch by Kevin Walzer. + What's New in IDLE 3.2.3? ========================= diff --git a/Lib/idlelib/configDialog.py b/Lib/idlelib/configDialog.py index 2701b42..434114e 100644 --- a/Lib/idlelib/configDialog.py +++ b/Lib/idlelib/configDialog.py @@ -821,10 +821,9 @@ class ConfigDialog(Toplevel): fontWeight=tkFont.BOLD else: fontWeight=tkFont.NORMAL - size=self.fontSize.get() - self.editFont.config(size=size, - weight=fontWeight,family=fontName) - self.textHighlightSample.configure(font=(fontName, size, fontWeight)) + newFont = (fontName, self.fontSize.get(), fontWeight) + self.labelFontSample.config(font=newFont) + self.textHighlightSample.configure(font=newFont) def SetHighlightTarget(self): if self.highlightTarget.get()=='Cursor': #bg not possible diff --git a/Lib/idlelib/help.txt b/Lib/idlelib/help.txt index 7bfd2ca..c179555 100644 --- a/Lib/idlelib/help.txt +++ b/Lib/idlelib/help.txt @@ -80,7 +80,7 @@ Shell Menu (only in Shell window): Debug Menu (only in Shell window): Go to File/Line -- look around the insert point for a filename - and linenumber, open the file, and show the line + and line number, open the file, and show the line Debugger (toggle) -- Run commands in the shell under the debugger Stack Viewer -- Show the stack traceback of the last exception Auto-open Stack Viewer (toggle) -- Open stack viewer on traceback @@ -92,7 +92,7 @@ Options Menu: Startup Preferences may be set, and Additional Help Sources can be specified. - On MacOS X this menu is not present, use + On OS X this menu is not present, use menu 'IDLE -> Preferences...' instead. --- Code Context -- Open a pane at the top of the edit window which @@ -120,6 +120,15 @@ Help Menu: --- (Additional Help Sources may be added here) +Edit context menu (Right-click / Control-click in Edit window): + + Set Breakpoint -- Sets a breakpoint (when debugger open) + Clear Breakpoint -- Clears the breakpoint on that line + +Shell context menu (Right-click / Control-click in Shell window): + + Go to file/line -- Same as in Debug menu + ** TIPS ** ========== @@ -222,7 +231,7 @@ Python Shell window: Alt-p retrieves previous command matching what you have typed. Alt-n retrieves next. - (These are Control-p, Control-n on the Mac) + (These are Control-p, Control-n on OS X) Return while cursor is on a previous command retrieves that command. Expand word is also useful to reduce typing. diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py index 29f2bf0..e098522 100755 --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -489,10 +489,10 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, next_single_test = alltests[alltests.index(selected[0])+1] except IndexError: next_single_test = None - # Remove all the tests that precede start if it's set. + # Remove all the selected tests that precede start if it's set. if start: try: - del tests[:tests.index(start)] + del selected[:selected.index(start)] except ValueError: print("Couldn't find starting test (%s), using all tests" % start) if randomize: diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py index be35580..715468a 100644 --- a/Lib/test/test_bz2.py +++ b/Lib/test/test_bz2.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 from test import support -from test.support import TESTFN +from test.support import TESTFN, _4G, bigmemtest, findfile import unittest from io import BytesIO @@ -25,6 +25,9 @@ class BaseTest(unittest.TestCase): DATA = b'BZh91AY&SY.\xc8N\x18\x00\x01>_\x80\x00\x10@\x02\xff\xf0\x01\x07n\x00?\xe7\xff\xe00\x01\x99\xaa\x00\xc0\x03F\x86\x8c#&\x83F\x9a\x03\x06\xa6\xd0\xa6\x93M\x0fQ\xa7\xa8\x06\x804hh\x12$\x11\xa4i4\xf14S\xd2<Q\xb5\x0fH\xd3\xd4\xdd\xd5\x87\xbb\xf8\x94\r\x8f\xafI\x12\xe1\xc9\xf8/E\x00pu\x89\x12]\xc9\xbbDL\nQ\x0e\t1\x12\xdf\xa0\xc0\x97\xac2O9\x89\x13\x94\x0e\x1c7\x0ed\x95I\x0c\xaaJ\xa4\x18L\x10\x05#\x9c\xaf\xba\xbc/\x97\x8a#C\xc8\xe1\x8cW\xf9\xe2\xd0\xd6M\xa7\x8bXa<e\x84t\xcbL\xb3\xa7\xd9\xcd\xd1\xcb\x84.\xaf\xb3\xab\xab\xad`n}\xa0lh\tE,\x8eZ\x15\x17VH>\x88\xe5\xcd9gd6\x0b\n\xe9\x9b\xd5\x8a\x99\xf7\x08.K\x8ev\xfb\xf7xw\xbb\xdf\xa1\x92\xf1\xdd|/";\xa2\xba\x9f\xd5\xb1#A\xb6\xf6\xb3o\xc9\xc5y\\\xebO\xe7\x85\x9a\xbc\xb6f8\x952\xd5\xd7"%\x89>V,\xf7\xa6z\xe2\x9f\xa3\xdf\x11\x11"\xd6E)I\xa9\x13^\xca\xf3r\xd0\x03U\x922\xf26\xec\xb6\xed\x8b\xc3U\x13\x9d\xc5\x170\xa4\xfa^\x92\xacDF\x8a\x97\xd6\x19\xfe\xdd\xb8\xbd\x1a\x9a\x19\xa3\x80ankR\x8b\xe5\xd83]\xa9\xc6\x08\x82f\xf6\xb9"6l$\xb8j@\xc0\x8a\xb0l1..\xbak\x83ls\x15\xbc\xf4\xc1\x13\xbe\xf8E\xb8\x9d\r\xa8\x9dk\x84\xd3n\xfa\xacQ\x07\xb1%y\xaav\xb4\x08\xe0z\x1b\x16\xf5\x04\xe9\xcc\xb9\x08z\x1en7.G\xfc]\xc9\x14\xe1B@\xbb!8`' DATA_CRLF = b'BZh91AY&SY\xaez\xbbN\x00\x01H\xdf\x80\x00\x12@\x02\xff\xf0\x01\x07n\x00?\xe7\xff\xe0@\x01\xbc\xc6`\x86*\x8d=M\xa9\x9a\x86\xd0L@\x0fI\xa6!\xa1\x13\xc8\x88jdi\x8d@\x03@\x1a\x1a\x0c\x0c\x83 \x00\xc4h2\x19\x01\x82D\x84e\t\xe8\x99\x89\x19\x1ah\x00\r\x1a\x11\xaf\x9b\x0fG\xf5(\x1b\x1f?\t\x12\xcf\xb5\xfc\x95E\x00ps\x89\x12^\xa4\xdd\xa2&\x05(\x87\x04\x98\x89u\xe40%\xb6\x19\'\x8c\xc4\x89\xca\x07\x0e\x1b!\x91UIFU%C\x994!DI\xd2\xfa\xf0\xf1N8W\xde\x13A\xf5\x9cr%?\x9f3;I45A\xd1\x8bT\xb1<l\xba\xcb_\xc00xY\x17r\x17\x88\x08\x08@\xa0\ry@\x10\x04$)`\xf2\xce\x89z\xb0s\xec\x9b.iW\x9d\x81\xb5-+t\x9f\x1a\'\x97dB\xf5x\xb5\xbe.[.\xd7\x0e\x81\xe7\x08\x1cN`\x88\x10\xca\x87\xc3!"\x80\x92R\xa1/\xd1\xc0\xe6mf\xac\xbd\x99\xcca\xb3\x8780>\xa4\xc7\x8d\x1a\\"\xad\xa1\xabyBg\x15\xb9l\x88\x88\x91k"\x94\xa4\xd4\x89\xae*\xa6\x0b\x10\x0c\xd6\xd4m\xe86\xec\xb5j\x8a\x86j\';\xca.\x01I\xf2\xaaJ\xe8\x88\x8cU+t3\xfb\x0c\n\xa33\x13r2\r\x16\xe0\xb3(\xbf\x1d\x83r\xe7M\xf0D\x1365\xd8\x88\xd3\xa4\x92\xcb2\x06\x04\\\xc1\xb0\xea//\xbek&\xd8\xe6+t\xe5\xa1\x13\xada\x16\xder5"w]\xa2i\xb7[\x97R \xe2IT\xcd;Z\x04dk4\xad\x8a\t\xd3\x81z\x10\xf1:^`\xab\x1f\xc5\xdc\x91N\x14$+\x9e\xae\xd3\x80' + with open(findfile("testbz2_bigmem.bz2"), "rb") as f: + DATA_BIGMEM = f.read() + if has_cmdline_bunzip2: def decompress(self, data): pop = subprocess.Popen("bunzip2", shell=True, @@ -44,6 +47,7 @@ class BaseTest(unittest.TestCase): def decompress(self, data): return bz2.decompress(data) + class BZ2FileTest(BaseTest): "Test BZ2File type miscellaneous methods." @@ -313,6 +317,17 @@ class BZ2CompressorTest(BaseTest): data += bz2c.flush() self.assertEqual(self.decompress(data), self.TEXT) + @bigmemtest(size=_4G, memuse=1.25) + def testBigmem(self, size): + text = b"a" * size + bz2c = bz2.BZ2Compressor() + data = bz2c.compress(text) + bz2c.flush() + del text + text = self.decompress(data) + self.assertEqual(len(text), size) + self.assertEqual(text.strip(b"a"), b"") + + class BZ2DecompressorTest(BaseTest): def test_Constructor(self): self.assertRaises(TypeError, BZ2Decompressor, 42) @@ -351,6 +366,13 @@ class BZ2DecompressorTest(BaseTest): text = bz2d.decompress(self.DATA) self.assertRaises(EOFError, bz2d.decompress, b"anything") + @bigmemtest(size=_4G, memuse=1.25, dry_run=False) + def testBigmem(self, unused_size): + # Issue #14398: decompression fails when output data is >=2GB. + text = bz2.BZ2Decompressor().decompress(self.DATA_BIGMEM) + self.assertEqual(len(text), _4G) + self.assertEqual(text.strip(b"\0"), b"") + class FuncTest(BaseTest): "Test module functions" @@ -374,6 +396,22 @@ class FuncTest(BaseTest): # "Test decompress() function with incomplete data" self.assertRaises(ValueError, bz2.decompress, self.DATA[:-10]) + @bigmemtest(size=_4G, memuse=1.25) + def testCompressBigmem(self, size): + text = b"a" * size + data = bz2.compress(text) + del text + text = self.decompress(data) + self.assertEqual(len(text), size) + self.assertEqual(text.strip(b"a"), b"") + + @bigmemtest(size=_4G, memuse=1.25, dry_run=False) + def testDecompressBigmem(self, unused_size): + # Issue #14398: decompression fails when output data is >=2GB. + text = bz2.decompress(self.DATA_BIGMEM) + self.assertEqual(len(text), _4G) + self.assertEqual(text.strip(b"\0"), b"") + def test_main(): support.run_unittest( BZ2FileTest, diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index f342d88..42d0da3 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -645,6 +645,8 @@ class UTF8Test(ReadTest): self.assertEqual(b"abc\xed\xa0\x80def".decode("utf-8", "surrogatepass"), "abc\ud800def") self.assertTrue(codecs.lookup_error("surrogatepass")) + with self.assertRaises(UnicodeDecodeError): + b"abc\xed\xa0".decode("utf-8", "surrogatepass") class UTF7Test(ReadTest): encoding = "utf-7" diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py index fb8261b..6d96550 100644 --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -19,39 +19,57 @@ except OSError: # This is what "no gdb" looks like. There may, however, be other # errors that manifest this way too. raise unittest.SkipTest("Couldn't find gdb on the path") -gdb_version_number = re.search(b"^GNU gdb [^\d]*(\d+)\.", gdb_version) -if int(gdb_version_number.group(1)) < 7: +gdb_version_number = re.search(b"^GNU gdb [^\d]*(\d+)\.(\d)", gdb_version) +gdb_major_version = int(gdb_version_number.group(1)) +gdb_minor_version = int(gdb_version_number.group(2)) +if gdb_major_version < 7: raise unittest.SkipTest("gdb versions before 7.0 didn't support python embedding" " Saw:\n" + gdb_version.decode('ascii', 'replace')) +# Location of custom hooks file in a repository checkout. +checkout_hook_path = os.path.join(os.path.dirname(sys.executable), + 'python-gdb.py') + +def run_gdb(*args, **env_vars): + """Runs gdb in --batch mode with the additional arguments given by *args. + + Returns its (stdout, stderr) decoded from utf-8 using the replace handler. + """ + if env_vars: + env = os.environ.copy() + env.update(env_vars) + else: + env = None + base_cmd = ('gdb', '--batch') + if (gdb_major_version, gdb_minor_version) >= (7, 4): + base_cmd += ('-iex', 'add-auto-load-safe-path ' + checkout_hook_path) + out, err = subprocess.Popen(base_cmd + args, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, + ).communicate() + return out.decode('utf-8', 'replace'), err.decode('utf-8', 'replace') + # Verify that "gdb" was built with the embedded python support enabled: -cmd = "--eval-command=python import sys; print sys.version_info" -p = subprocess.Popen(["gdb", "--batch", cmd], - stdout=subprocess.PIPE) -gdbpy_version, _ = p.communicate() -if gdbpy_version == b'': +gdbpy_version, _ = run_gdb("--eval-command=python import sys; print sys.version_info") +if not gdbpy_version: raise unittest.SkipTest("gdb not built with embedded python support") -# Verify that "gdb" can load our custom hooks -p = subprocess.Popen(["gdb", "--batch", cmd, - "--args", sys.executable], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) -__, gdbpy_errors = p.communicate() -if b"auto-loading has been declined" in gdbpy_errors: - msg = "gdb security settings prevent use of custom hooks: %s" - raise unittest.SkipTest(msg % gdbpy_errors) +# Verify that "gdb" can load our custom hooks. In theory this should never +# fail, but we don't handle the case of the hooks file not existing if the +# tests are run from an installed Python (we'll produce failures in that case). +cmd = ['--args', sys.executable] +_, gdbpy_errors = run_gdb('--args', sys.executable) +if "auto-loading has been declined" in gdbpy_errors: + msg = "gdb security settings prevent use of custom hooks: " + raise unittest.SkipTest(msg + gdbpy_errors.rstrip()) def gdb_has_frame_select(): # Does this build of gdb have gdb.Frame.select ? - cmd = "--eval-command=python print(dir(gdb.Frame))" - p = subprocess.Popen(["gdb", "--batch", cmd], - stdout=subprocess.PIPE) - stdout, _ = p.communicate() - m = re.match(br'.*\[(.*)\].*', stdout) + stdout, _ = run_gdb("--eval-command=python print(dir(gdb.Frame))") + m = re.match(r'.*\[(.*)\].*', stdout) if not m: raise unittest.SkipTest("Unable to parse output from gdb.Frame.select test") - gdb_frame_dir = m.group(1).split(b', ') - return b"'select'" in gdb_frame_dir + gdb_frame_dir = m.group(1).split(', ') + return "'select'" in gdb_frame_dir HAS_PYUP_PYDOWN = gdb_has_frame_select() @@ -61,21 +79,6 @@ class DebuggerTests(unittest.TestCase): """Test that the debugger can debug Python.""" - def run_gdb(self, *args, **env_vars): - """Runs gdb with the command line given by *args. - - Returns its stdout, stderr - """ - if env_vars: - env = os.environ.copy() - env.update(env_vars) - else: - env = None - out, err = subprocess.Popen( - args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, - ).communicate() - return out.decode('utf-8', 'replace'), err.decode('utf-8', 'replace') - def get_stack_trace(self, source=None, script=None, breakpoint=BREAKPOINT_FN, cmds_after_breakpoint=None, @@ -132,7 +135,7 @@ class DebuggerTests(unittest.TestCase): # print ' '.join(args) # Use "args" to invoke gdb, capturing stdout, stderr: - out, err = self.run_gdb(*args, PYTHONHASHSEED='0') + out, err = run_gdb(*args, PYTHONHASHSEED='0') # Ignore some noise on stderr due to the pending breakpoint: err = err.replace('Function "%s" not defined.\n' % breakpoint, '') @@ -149,6 +152,11 @@ class DebuggerTests(unittest.TestCase): 'Do you need "set solib-search-path" or ' '"set sysroot"?\n', '') + err = err.replace('warning: Could not load shared library symbols for ' + 'linux-gate.so.1.\n' + 'Do you need "set solib-search-path" or ' + '"set sysroot"?\n', + '') # Ensure no unexpected error messages: self.assertEqual(err, '') diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py index 0f8f1f5..b10f350 100644 --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -20,12 +20,23 @@ from test.support import ( from test import script_helper +def _files(name): + return (name + os.extsep + "py", + name + os.extsep + "pyc", + name + os.extsep + "pyo", + name + os.extsep + "pyw", + name + "$py.class") + +def chmod_files(name): + for f in _files(name): + try: + os.chmod(f, 0o600) + except OSError as exc: + if exc.errno != errno.ENOENT: + raise + def remove_files(name): - for f in (name + ".py", - name + ".pyc", - name + ".pyo", - name + ".pyw", - name + "$py.class"): + for f in _files(name): unlink(f) rmtree('__pycache__') @@ -122,6 +133,45 @@ class ImportTests(unittest.TestCase): remove_files(TESTFN) unload(TESTFN) + def test_rewrite_pyc_with_read_only_source(self): + # Issue 6074: a long time ago on posix, and more recently on Windows, + # a read only source file resulted in a read only pyc file, which + # led to problems with updating it later + sys.path.insert(0, os.curdir) + fname = TESTFN + os.extsep + "py" + try: + # Write a Python file, make it read-only and import it + with open(fname, 'w') as f: + f.write("x = 'original'\n") + # Tweak the mtime of the source to ensure pyc gets updated later + s = os.stat(fname) + os.utime(fname, (s.st_atime, s.st_mtime-100000000)) + os.chmod(fname, 0o400) + m1 = __import__(TESTFN) + self.assertEqual(m1.x, 'original') + # Change the file and then reimport it + os.chmod(fname, 0o600) + with open(fname, 'w') as f: + f.write("x = 'rewritten'\n") + unload(TESTFN) + m2 = __import__(TESTFN) + self.assertEqual(m2.x, 'rewritten') + # Now delete the source file and check the pyc was rewritten + unlink(fname) + unload(TESTFN) + if __debug__: + bytecode_name = fname + "c" + else: + bytecode_name = fname + "o" + os.rename(imp.cache_from_source(fname), bytecode_name) + m3 = __import__(TESTFN) + self.assertEqual(m3.x, 'rewritten') + finally: + chmod_files(TESTFN) + remove_files(TESTFN) + unload(TESTFN) + del sys.path[0] + def test_imp_module(self): # Verify that the imp module can correctly load and find .py files # XXX (ncoghlan): It would be nice to use support.CleanImport diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 19b06a0..000ae6a 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -906,6 +906,21 @@ class UnicodeTest(string_tests.CommonTest, self.assertRaises(ValueError, '{}'.format_map, 'a') self.assertRaises(ValueError, '{a} {}'.format_map, {"a" : 2, "b" : 1}) + def test_format_huge_precision(self): + format_string = ".{}f".format(sys.maxsize + 1) + with self.assertRaises(ValueError): + result = format(2.34, format_string) + + def test_format_huge_width(self): + format_string = "{}f".format(sys.maxsize + 1) + with self.assertRaises(ValueError): + result = format(2.34, format_string) + + def test_format_huge_item_number(self): + format_string = "{{{}:.6f}}".format(sys.maxsize + 1) + with self.assertRaises(ValueError): + result = format_string.format(2.34) + def test_format_auto_numbering(self): class C: def __init__(self, x=100): @@ -990,6 +1005,18 @@ class UnicodeTest(string_tests.CommonTest, self.assertEqual('%f' % INF, 'inf') self.assertEqual('%F' % INF, 'INF') + @support.cpython_only + def test_formatting_huge_precision(self): + from _testcapi import INT_MAX + format_string = "%.{}f".format(INT_MAX + 1) + with self.assertRaises(ValueError): + result = format_string % 2.34 + + def test_formatting_huge_width(self): + format_string = "%{}f".format(sys.maxsize + 1) + with self.assertRaises(ValueError): + result = format_string % 2.34 + def test_startswith_endswith_errors(self): for meth in ('foo'.startswith, 'foo'.endswith): with self.assertRaises(TypeError) as cm: diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py index c6f6f61..3fc499e 100644 --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -268,6 +268,41 @@ Content-Type: text/html; charset=iso-8859-1 finally: self.unfakehttp() + def test_missing_localfile(self): + # Test for #10836 + with self.assertRaises(urllib.error.URLError) as e: + urlopen('file://localhost/a/file/which/doesnot/exists.py') + self.assertTrue(e.exception.filename) + self.assertTrue(e.exception.reason) + + def test_file_notexists(self): + fd, tmp_file = tempfile.mkstemp() + tmp_fileurl = 'file://localhost/' + tmp_file.replace(os.path.sep, '/') + try: + self.assertTrue(os.path.exists(tmp_file)) + with urlopen(tmp_fileurl) as fobj: + self.assertTrue(fobj) + finally: + os.close(fd) + os.unlink(tmp_file) + self.assertFalse(os.path.exists(tmp_file)) + with self.assertRaises(urllib.error.URLError): + urlopen(tmp_fileurl) + + def test_ftp_nohost(self): + test_ftp_url = 'ftp:///path' + with self.assertRaises(urllib.error.URLError) as e: + urlopen(test_ftp_url) + self.assertFalse(e.exception.filename) + self.assertTrue(e.exception.reason) + + def test_ftp_nonexisting(self): + with self.assertRaises(urllib.error.URLError) as e: + urlopen('ftp://localhost/a/file/which/doesnot/exists.py') + self.assertFalse(e.exception.filename) + self.assertTrue(e.exception.reason) + + def test_userpass_inurl(self): self.fakehttp(b"HTTP/1.0 200 OK\r\n\r\nHello!") try: diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py index 5fcb4cb..e2b1d95 100644 --- a/Lib/test/test_urllib2net.py +++ b/Lib/test/test_urllib2net.py @@ -156,12 +156,12 @@ class OtherNetworkTests(unittest.TestCase): ## self._test_urls(urls, self._extra_handlers()+[bauth, dauth]) def test_urlwithfrag(self): - urlwith_frag = "http://docs.python.org/glossary.html#glossary" + urlwith_frag = "http://docs.python.org/2/glossary.html#glossary" with support.transient_internet(urlwith_frag): req = urllib.request.Request(urlwith_frag) res = urllib.request.urlopen(req) self.assertEqual(res.geturl(), - "http://docs.python.org/glossary.html#glossary") + "http://docs.python.org/2/glossary.html#glossary") def test_custom_headers(self): url = "http://www.example.com" diff --git a/Lib/test/test_wsgiref.py b/Lib/test/test_wsgiref.py index a08f66b..08f8d9a 100644 --- a/Lib/test/test_wsgiref.py +++ b/Lib/test/test_wsgiref.py @@ -39,9 +39,6 @@ class MockHandler(WSGIRequestHandler): pass - - - def hello_app(environ,start_response): start_response("200 OK", [ ('Content-Type','text/plain'), @@ -63,28 +60,6 @@ def run_amock(app=hello_app, data=b"GET / HTTP/1.0\n\n"): return out.getvalue(), err.getvalue() - - - - - - - - - - - - - - - - - - - - - - def compare_generic_iter(make_it,match): """Utility to compare a generic 2.1/2.2+ iterator with an iterable @@ -122,10 +97,6 @@ def compare_generic_iter(make_it,match): raise AssertionError("Too many items from .__next__()", it) - - - - class IntegrationTests(TestCase): def check_hello(self, out, has_length=True): @@ -195,8 +166,6 @@ class IntegrationTests(TestCase): out) - - class UtilityTests(TestCase): def checkShift(self,sn_in,pi_in,part,sn_out,pi_out): @@ -235,11 +204,6 @@ class UtilityTests(TestCase): util.setup_testing_defaults(kw) self.assertEqual(util.request_uri(kw,query),uri) - - - - - def checkFW(self,text,size,match): def make_it(text=text,size=size): @@ -258,7 +222,6 @@ class UtilityTests(TestCase): it.close() self.assertTrue(it.filelike.closed) - def testSimpleShifts(self): self.checkShift('','/', '', '/', '') self.checkShift('','/x', 'x', '/x', '') @@ -266,7 +229,6 @@ class UtilityTests(TestCase): self.checkShift('/a','/x/y', 'x', '/a/x', '/y') self.checkShift('/a','/x/', 'x', '/a/x', '/') - def testNormalizedShifts(self): self.checkShift('/a/b', '/../y', '..', '/a', '/y') self.checkShift('', '/../y', '..', '', '/y') @@ -280,7 +242,6 @@ class UtilityTests(TestCase): self.checkShift('/a/b', '/x//', 'x', '/a/b/x', '/') self.checkShift('/a/b', '/.', None, '/a/b', '') - def testDefaults(self): for key, value in [ ('SERVER_NAME','127.0.0.1'), @@ -300,7 +261,6 @@ class UtilityTests(TestCase): ]: self.checkDefault(key,value) - def testCrossDefaults(self): self.checkCrossDefault('HTTP_HOST',"foo.bar",SERVER_NAME="foo.bar") self.checkCrossDefault('wsgi.url_scheme',"https",HTTPS="on") @@ -310,7 +270,6 @@ class UtilityTests(TestCase): self.checkCrossDefault('SERVER_PORT',"80",HTTPS="foo") self.checkCrossDefault('SERVER_PORT',"443",HTTPS="on") - def testGuessScheme(self): self.assertEqual(util.guess_scheme({}), "http") self.assertEqual(util.guess_scheme({'HTTPS':"foo"}), "http") @@ -318,10 +277,6 @@ class UtilityTests(TestCase): self.assertEqual(util.guess_scheme({'HTTPS':"yes"}), "https") self.assertEqual(util.guess_scheme({'HTTPS':"1"}), "https") - - - - def testAppURIs(self): self.checkAppURI("http://127.0.0.1/") self.checkAppURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam") @@ -446,15 +401,6 @@ class TestHandler(ErrorHandler): raise # for testing, we want to see what's happening - - - - - - - - - class HandlerTests(TestCase): def checkEnvironAttrs(self, handler): @@ -495,7 +441,6 @@ class HandlerTests(TestCase): h=TestHandler(); h.setup_environ() self.assertEqual(h.environ['wsgi.url_scheme'],'http') - def testAbstractMethods(self): h = BaseHandler() for name in [ @@ -504,7 +449,6 @@ class HandlerTests(TestCase): self.assertRaises(NotImplementedError, getattr(h,name)) self.assertRaises(NotImplementedError, h._write, "test") - def testContentLength(self): # Demo one reason iteration is better than write()... ;) @@ -596,7 +540,6 @@ class HandlerTests(TestCase): "\r\n".encode("iso-8859-1")+MSG)) self.assertIn("AssertionError", h.stderr.getvalue()) - def testHeaderFormats(self): def non_error_app(e,s): @@ -656,40 +599,27 @@ class HandlerTests(TestCase): b"data", h.stdout.getvalue()) -# This epilogue is needed for compatibility with the Python 2.5 regrtest module + def testCloseOnError(self): + side_effects = {'close_called': False} + MSG = b"Some output has been sent" + def error_app(e,s): + s("200 OK",[])(MSG) + class CrashyIterable(object): + def __iter__(self): + while True: + yield b'blah' + raise AssertionError("This should be caught by handler") + def close(self): + side_effects['close_called'] = True + return CrashyIterable() + + h = ErrorHandler() + h.run(error_app) + self.assertEqual(side_effects['close_called'], True) + def test_main(): support.run_unittest(__name__) if __name__ == "__main__": test_main() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# the above lines intentionally left blank diff --git a/Lib/test/testbz2_bigmem.bz2 b/Lib/test/testbz2_bigmem.bz2 Binary files differnew file mode 100644 index 0000000..c9a4616 --- /dev/null +++ b/Lib/test/testbz2_bigmem.bz2 diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index d6f9f9a..eb45c7e 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -1300,9 +1300,9 @@ class FileHandler(BaseHandler): else: origurl = 'file://' + filename return addinfourl(open(localfile, 'rb'), headers, origurl) - except OSError as msg: + except OSError as exp: # users shouldn't expect OSErrors coming from urlopen() - raise URLError(msg) + raise URLError(exp) raise URLError('file not on local host') def _safe_gethostbyname(host): @@ -1361,8 +1361,8 @@ class FTPHandler(BaseHandler): headers += "Content-length: %d\n" % retrlen headers = email.message_from_string(headers) return addinfourl(fp, headers, req.full_url) - except ftplib.all_errors as msg: - exc = URLError('ftp error: %s' % msg) + except ftplib.all_errors as exp: + exc = URLError('ftp error: %r' % exp) raise exc.with_traceback(sys.exc_info()[2]) def connect_ftp(self, user, passwd, host, port, dirs, timeout): @@ -1662,7 +1662,6 @@ class URLopener: if proxy_bypass(realhost): host = realhost - #print "proxy via http:", host, selector if not host: raise IOError('http error', 'no host given') if proxy_passwd: @@ -1753,7 +1752,7 @@ class URLopener: def open_file(self, url): """Use local file or FTP depending on form of URL.""" if not isinstance(url, str): - raise URLError('file error', 'proxy support for file protocol currently not implemented') + raise URLError('file error: proxy support for file protocol currently not implemented') if url[:2] == '//' and url[2:3] != '/' and url[2:12].lower() != 'localhost/': raise ValueError("file:// scheme is supported only on localhost") else: @@ -1768,7 +1767,7 @@ class URLopener: try: stats = os.stat(localname) except OSError as e: - raise URLError(e.errno, e.strerror, e.filename) + raise URLError(e.strerror, e.filename) size = stats.st_size modified = email.utils.formatdate(stats.st_mtime, usegmt=True) mtype = mimetypes.guess_type(url)[0] @@ -1782,23 +1781,22 @@ class URLopener: return addinfourl(open(localname, 'rb'), headers, urlfile) host, port = splitport(host) if (not port - and socket.gethostbyname(host) in (localhost() + thishost())): + and socket.gethostbyname(host) in ((localhost(),) + thishost())): urlfile = file if file[:1] == '/': urlfile = 'file://' + file elif file[:2] == './': raise ValueError("local file url may start with / or file:. Unknown url of type: %s" % url) return addinfourl(open(localname, 'rb'), headers, urlfile) - raise URLError('local file error', 'not on local host') + raise URLError('local file error: not on local host') def open_ftp(self, url): """Use FTP protocol.""" if not isinstance(url, str): - raise URLError('ftp error', 'proxy support for ftp protocol currently not implemented') + raise URLError('ftp error: proxy support for ftp protocol currently not implemented') import mimetypes - from io import StringIO host, path = splithost(url) - if not host: raise URLError('ftp error', 'no host given') + if not host: raise URLError('ftp error: no host given') host, port = splitport(host) user, host = splituser(host) if user: user, passwd = splitpasswd(user) @@ -1847,13 +1845,13 @@ class URLopener: headers += "Content-Length: %d\n" % retrlen headers = email.message_from_string(headers) return addinfourl(fp, headers, "ftp:" + url) - except ftperrors() as msg: - raise URLError('ftp error', msg).with_traceback(sys.exc_info()[2]) + except ftperrors() as exp: + raise URLError('ftp error %r' % exp).with_traceback(sys.exc_info()[2]) def open_data(self, url, data=None): """Use "data" URL.""" if not isinstance(url, str): - raise URLError('data error', 'proxy support for data protocol currently not implemented') + raise URLError('data error: proxy support for data protocol currently not implemented') # ignore POSTed data # # syntax of data URLs: @@ -2184,7 +2182,7 @@ class ftpwrapper: conn, retrlen = self.ftp.ntransfercmd(cmd) except ftplib.error_perm as reason: if str(reason)[:3] != '550': - raise URLError('ftp error', reason).with_traceback( + raise URLError('ftp error: %d' % reason).with_traceback( sys.exc_info()[2]) if not conn: # Set transfer mode to ASCII! @@ -2196,7 +2194,7 @@ class ftpwrapper: try: self.ftp.cwd(file) except ftplib.error_perm as reason: - raise URLError('ftp error', reason) from reason + raise URLError('ftp error: %d' % reason) from reason finally: self.ftp.cwd(pwd) cmd = 'LIST ' + file @@ -2212,13 +2210,7 @@ class ftpwrapper: return (ftpobj, retrlen) def endtransfer(self): - if not self.busy: - return self.busy = 0 - try: - self.ftp.voidresp() - except ftperrors(): - pass def close(self): self.keepalive = False @@ -2470,7 +2462,6 @@ elif os.name == 'nt': test = test.replace("*", r".*") # change glob sequence test = test.replace("?", r".") # change glob char for val in host: - # print "%s <--> %s" %( test, val ) if re.match(test, val, re.I): return 1 return 0 diff --git a/Lib/wsgiref/handlers.py b/Lib/wsgiref/handlers.py index 67064a6..63d5993 100644 --- a/Lib/wsgiref/handlers.py +++ b/Lib/wsgiref/handlers.py @@ -174,11 +174,13 @@ class BaseHandler: in the event loop to iterate over the data, and to call 'self.close()' once the response is finished. """ - if not self.result_is_file() or not self.sendfile(): - for data in self.result: - self.write(data) - self.finish_content() - self.close() + try: + if not self.result_is_file() or not self.sendfile(): + for data in self.result: + self.write(data) + self.finish_content() + finally: + self.close() def get_scheme(self): |