diff options
Diffstat (limited to 'Lib')
| -rw-r--r-- | Lib/_pyio.py | 3 | ||||
| -rwxr-xr-x | Lib/cgi.py | 5 | ||||
| -rw-r--r-- | Lib/configparser.py | 29 | ||||
| -rw-r--r-- | Lib/functools.py | 2 | ||||
| -rw-r--r-- | Lib/http/server.py | 3 | ||||
| -rw-r--r-- | Lib/idlelib/NEWS.txt | 13 | ||||
| -rw-r--r-- | Lib/idlelib/ScriptBinding.py | 2 | ||||
| -rw-r--r-- | Lib/idlelib/StackViewer.py | 11 | ||||
| -rw-r--r-- | Lib/idlelib/configDialog.py | 85 | ||||
| -rw-r--r-- | Lib/test/test_cgi.py | 18 | ||||
| -rw-r--r-- | Lib/test/test_configparser.py | 7 | ||||
| -rw-r--r-- | Lib/test/test_deque.py | 5 | ||||
| -rw-r--r-- | Lib/test/test_functools.py | 18 | ||||
| -rw-r--r-- | Lib/unittest/case.py | 25 | ||||
| -rw-r--r-- | Lib/unittest/test/test_assertions.py | 15 | ||||
| -rw-r--r-- | Lib/unittest/test/test_skipping.py | 33 |
16 files changed, 200 insertions, 74 deletions
diff --git a/Lib/_pyio.py b/Lib/_pyio.py index 50ad9ff..f47df91 100644 --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -8,12 +8,13 @@ import codecs import errno import array import stat +import sys # Import _thread instead of threading to reduce startup cost try: from _thread import allocate_lock as Lock except ImportError: from _dummy_thread import allocate_lock as Lock -if os.name == 'win32': +if sys.platform in {'win32', 'cygwin'}: from msvcrt import setmode as _setmode else: _setmode = None @@ -720,6 +720,11 @@ class FieldStorage: self.bytes_read += len(hdr_text) parser.feed(hdr_text.decode(self.encoding, self.errors)) headers = parser.close() + + # Some clients add Content-Length for part headers, ignore them + if 'content-length' in headers: + del headers['content-length'] + part = klass(self.fp, headers, ib, environ, keep_blank_values, strict_parsing,self.limit-self.bytes_read, self.encoding, self.errors) diff --git a/Lib/configparser.py b/Lib/configparser.py index ecd0660..3a9fb56 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -263,12 +263,9 @@ class InterpolationMissingOptionError(InterpolationError): """A string substitution required a setting which was not available.""" def __init__(self, option, section, rawval, reference): - msg = ("Bad value substitution:\n" - "\tsection: [%s]\n" - "\toption : %s\n" - "\tkey : %s\n" - "\trawval : %s\n" - % (section, option, reference, rawval)) + msg = ("Bad value substitution: option {!r} in section {!r} contains " + "an interpolation key {!r} which is not a valid option name. " + "Raw value: {!r}".format(option, section, reference, rawval)) InterpolationError.__init__(self, option, section, msg) self.reference = reference self.args = (option, section, rawval, reference) @@ -286,11 +283,11 @@ class InterpolationDepthError(InterpolationError): """Raised when substitutions are nested too deeply.""" def __init__(self, option, section, rawval): - msg = ("Value interpolation too deeply recursive:\n" - "\tsection: [%s]\n" - "\toption : %s\n" - "\trawval : %s\n" - % (section, option, rawval)) + msg = ("Recursion limit exceeded in value substitution: option {!r} " + "in section {!r} contains an interpolation key which " + "cannot be substituted in {} steps. Raw value: {!r}" + "".format(option, section, MAX_INTERPOLATION_DEPTH, + rawval)) InterpolationError.__init__(self, option, section, msg) self.args = (option, section, rawval) @@ -406,8 +403,9 @@ class BasicInterpolation(Interpolation): def _interpolate_some(self, parser, option, accum, rest, section, map, depth): + rawval = parser.get(section, option, raw=True, fallback=rest) if depth > MAX_INTERPOLATION_DEPTH: - raise InterpolationDepthError(option, section, rest) + raise InterpolationDepthError(option, section, rawval) while rest: p = rest.find("%") if p < 0: @@ -432,7 +430,7 @@ class BasicInterpolation(Interpolation): v = map[var] except KeyError: raise InterpolationMissingOptionError( - option, section, rest, var) from None + option, section, rawval, var) from None if "%" in v: self._interpolate_some(parser, option, accum, v, section, map, depth + 1) @@ -466,8 +464,9 @@ class ExtendedInterpolation(Interpolation): def _interpolate_some(self, parser, option, accum, rest, section, map, depth): + rawval = parser.get(section, option, raw=True, fallback=rest) if depth > MAX_INTERPOLATION_DEPTH: - raise InterpolationDepthError(option, section, rest) + raise InterpolationDepthError(option, section, rawval) while rest: p = rest.find("$") if p < 0: @@ -504,7 +503,7 @@ class ExtendedInterpolation(Interpolation): "More than one ':' found: %r" % (rest,)) except (KeyError, NoSectionError, NoOptionError): raise InterpolationMissingOptionError( - option, section, rest, ":".join(path)) from None + option, section, rawval, ":".join(path)) from None if "$" in v: self._interpolate_some(parser, opt, accum, v, sect, dict(parser.items(sect, raw=True)), diff --git a/Lib/functools.py b/Lib/functools.py index 09df068..06a4ff1 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -567,7 +567,7 @@ def _c3_merge(sequences): break # reject the current head, it appears later else: break - if not candidate: + if candidate is None: raise RuntimeError("Inconsistent hierarchy") result.append(candidate) # remove the chosen candidate diff --git a/Lib/http/server.py b/Lib/http/server.py index fd13be3..6a0e6fe 100644 --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -1167,8 +1167,7 @@ def test(HandlerClass=BaseHTTPRequestHandler, ServerClass=HTTPServer, protocol="HTTP/1.0", port=8000, bind=""): """Test the HTTP request handler class. - This runs an HTTP server on port 8000 (or the first command line - argument). + This runs an HTTP server on port 8000 (or the port argument). """ server_address = (bind, port) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 2d8ce54..be063c4 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -2,6 +2,19 @@ What's New in IDLE 3.5.0? ========================= *Release date: 2015-09-13* ?? +- Issue #23672: Allow Idle to edit and run files with astral chars in name. + Patch by Mohd Sanad Zaki Rizvi. + +- Issue 24745: Idle editor default font. Switch from Courier to + platform-sensitive TkFixedFont. This should not affect current customized + font selections. If there is a problem, edit $HOME/.idlerc/config-main.cfg + and remove 'fontxxx' entries from [Editor Window]. Patch by Mark Roseman. + +- Issue #21192: Idle editor. When a file is run, put its name in the restart bar. + Do not print false prompts. Original patch by Adnan Umer. + +- Issue #13884: Idle menus. Remove tearoff lines. Patch by Roger Serwy. + - Issue #23184: remove unused names and imports in idlelib. Initial patch by Al Sweigart. diff --git a/Lib/idlelib/ScriptBinding.py b/Lib/idlelib/ScriptBinding.py index e8cb2fc..e5636df 100644 --- a/Lib/idlelib/ScriptBinding.py +++ b/Lib/idlelib/ScriptBinding.py @@ -69,7 +69,7 @@ class ScriptBinding: try: tabnanny.process_tokens(tokenize.generate_tokens(f.readline)) except tokenize.TokenError as msg: - msgtxt, (lineno, start) = msg + msgtxt, (lineno, start) = msg.args self.editwin.gotoline(lineno) self.errorbox("Tabnanny Tokenizing Error", "Token Error: %s" % msgtxt) diff --git a/Lib/idlelib/StackViewer.py b/Lib/idlelib/StackViewer.py index b1e5e26..ccc755c 100644 --- a/Lib/idlelib/StackViewer.py +++ b/Lib/idlelib/StackViewer.py @@ -10,8 +10,7 @@ from idlelib.PyShell import PyShellFileList def StackBrowser(root, flist=None, tb=None, top=None): if top is None: - from tkinter import Toplevel - top = Toplevel(root) + top = tk.Toplevel(root) sc = ScrolledCanvas(top, bg="white", highlightthickness=0) sc.frame.pack(expand=1, fill="both") item = StackTreeItem(flist, tb) @@ -108,12 +107,9 @@ class VariablesTreeItem(ObjectTreeItem): def IsExpandable(self): return len(self.object) > 0 - def keys(self): - return list(self.object.keys()) - def GetSubList(self): sublist = [] - for key in self.keys(): + for key in self.object.keys(): try: value = self.object[key] except KeyError: @@ -124,6 +120,9 @@ class VariablesTreeItem(ObjectTreeItem): sublist.append(item) return sublist + def keys(self): # unused, left for possible 3rd party use + return list(self.object.keys()) + def _stack_viewer(parent): root = tk.Tk() root.title("Test StackViewer") diff --git a/Lib/idlelib/configDialog.py b/Lib/idlelib/configDialog.py index 9ed6336..b70cb60 100644 --- a/Lib/idlelib/configDialog.py +++ b/Lib/idlelib/configDialog.py @@ -1201,9 +1201,6 @@ class VerticalScrolledFrame(Frame): # update the scrollbars to match the size of the inner frame size = (interior.winfo_reqwidth(), interior.winfo_reqheight()) canvas.config(scrollregion="0 0 %s %s" % size) - if interior.winfo_reqwidth() != canvas.winfo_width(): - # update the canvas's width to fit the inner frame - canvas.config(width=interior.winfo_reqwidth()) interior.bind('<Configure>', _configure_interior) def _configure_canvas(event): @@ -1323,38 +1320,56 @@ class ConfigExtensionsDialog(Toplevel): def create_widgets(self): """Create the dialog's widgets.""" + self.extension_names = StringVar(self) self.rowconfigure(0, weight=1) - self.rowconfigure(1, weight=0) - self.columnconfigure(0, weight=1) - - # create the tabbed pages - self.tabbed_page_set = TabbedPageSet( - self, page_names=self.extensions.keys(), - n_rows=None, max_tabs_per_row=5, - page_class=TabbedPageSet.PageRemove) - self.tabbed_page_set.grid(row=0, column=0, sticky=NSEW) - for ext_name in self.extensions: - self.create_tab_page(ext_name) - - self.create_action_buttons().grid(row=1) + self.columnconfigure(2, weight=1) + self.extension_list = Listbox(self, listvariable=self.extension_names, + selectmode='browse') + self.extension_list.bind('<<ListboxSelect>>', self.extension_selected) + scroll = Scrollbar(self, command=self.extension_list.yview) + self.extension_list.yscrollcommand=scroll.set + self.details_frame = LabelFrame(self, width=250, height=250) + self.extension_list.grid(column=0, row=0, sticky='nws') + scroll.grid(column=1, row=0, sticky='ns') + self.details_frame.grid(column=2, row=0, sticky='nsew', padx=[10, 0]) + self.configure(padx=10, pady=10) + self.config_frame = {} + self.current_extension = None + + self.outerframe = self # TEMPORARY + self.tabbed_page_set = self.extension_list # TEMPORARY + + # create the individual pages + ext_names = '' + for ext_name in sorted(self.extensions): + self.create_extension_frame(ext_name) + ext_names = ext_names + '{' + ext_name + '} ' + self.extension_names.set(ext_names) + self.extension_list.selection_set(0) + self.extension_selected(None) + self.create_action_buttons().grid(row=1, columnspan=3) + + def extension_selected(self, event): + newsel = self.extension_list.curselection() + if newsel: + newsel = self.extension_list.get(newsel) + if newsel is None or newsel != self.current_extension: + if self.current_extension: + self.details_frame.config(text='') + self.config_frame[self.current_extension].grid_forget() + self.current_extension = None + if newsel: + self.details_frame.config(text=newsel) + self.config_frame[newsel].grid(column=0, row=0, sticky='nsew') + self.current_extension = newsel create_action_buttons = ConfigDialog.create_action_buttons - def create_tab_page(self, ext_name): - """Create the page for an extension.""" - - page = LabelFrame(self.tabbed_page_set.pages[ext_name].frame, - border=2, padx=2, relief=GROOVE, - text=' %s ' % ext_name) - page.pack(fill=BOTH, expand=True, padx=12, pady=2) - - # create the scrollable frame which will contain the entries - scrolled_frame = VerticalScrolledFrame(page, pady=2, height=250) - scrolled_frame.pack(side=BOTTOM, fill=BOTH, expand=TRUE) - entry_area = scrolled_frame.interior - entry_area.columnconfigure(0, weight=0) - entry_area.columnconfigure(1, weight=1) - + def create_extension_frame(self, ext_name): + """Create a frame holding the widgets to configure one extension""" + f = VerticalScrolledFrame(self.details_frame, height=250, width=250) + self.config_frame[ext_name] = f + entry_area = f.interior # create an entry for each configuration option for row, opt in enumerate(self.extensions[ext_name]): # create a row with a label and entry/checkbutton @@ -1365,15 +1380,15 @@ class ConfigExtensionsDialog(Toplevel): Checkbutton(entry_area, textvariable=var, variable=var, onvalue='True', offvalue='False', indicatoron=FALSE, selectcolor='', width=8 - ).grid(row=row, column=1, sticky=W, padx=7) + ).grid(row=row, column=1, sticky=W, padx=7) elif opt['type'] == 'int': Entry(entry_area, textvariable=var, validate='key', - validatecommand=(self.is_int, '%P') - ).grid(row=row, column=1, sticky=NSEW, padx=7) + validatecommand=(self.is_int, '%P') + ).grid(row=row, column=1, sticky=NSEW, padx=7) else: Entry(entry_area, textvariable=var - ).grid(row=row, column=1, sticky=NSEW, padx=7) + ).grid(row=row, column=1, sticky=NSEW, padx=7) return diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py index a7a9d02..ab9f6ab 100644 --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -326,6 +326,24 @@ Content-Type: text/plain got = getattr(files[x], k) self.assertEqual(got, exp) + def test_fieldstorage_part_content_length(self): + BOUNDARY = "JfISa01" + POSTDATA = """--JfISa01 +Content-Disposition: form-data; name="submit-name" +Content-Length: 5 + +Larry +--JfISa01""" + env = { + 'REQUEST_METHOD': 'POST', + 'CONTENT_TYPE': 'multipart/form-data; boundary={}'.format(BOUNDARY), + 'CONTENT_LENGTH': str(len(POSTDATA))} + fp = BytesIO(POSTDATA.encode('latin-1')) + fs = cgi.FieldStorage(fp, environ=env, encoding="latin-1") + self.assertEqual(len(fs.list), 1) + self.assertEqual(fs.list[0].name, 'submit-name') + self.assertEqual(fs.list[0].value, 'Larry') + def test_fieldstorage_as_context_manager(self): fp = BytesIO(b'x' * 10) env = {'REQUEST_METHOD': 'PUT'} diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py index 470d2cd..71a8f3f 100644 --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -847,7 +847,8 @@ class ConfigParserTestCase(BasicTestCase, unittest.TestCase): "something with lots of interpolation (10 steps)") e = self.get_error(cf, configparser.InterpolationDepthError, "Foo", "bar11") if self.interpolation == configparser._UNSET: - self.assertEqual(e.args, ("bar11", "Foo", "%(with1)s")) + self.assertEqual(e.args, ("bar11", "Foo", + "something %(with11)s lots of interpolation (11 steps)")) elif isinstance(self.interpolation, configparser.LegacyInterpolation): self.assertEqual(e.args, ("bar11", "Foo", "something %(with11)s lots of interpolation (11 steps)")) @@ -861,7 +862,7 @@ class ConfigParserTestCase(BasicTestCase, unittest.TestCase): self.assertEqual(e.option, "name") if self.interpolation == configparser._UNSET: self.assertEqual(e.args, ('name', 'Interpolation Error', - '', 'reference')) + '%(reference)s', 'reference')) elif isinstance(self.interpolation, configparser.LegacyInterpolation): self.assertEqual(e.args, ('name', 'Interpolation Error', '%(reference)s', 'reference')) @@ -1177,7 +1178,7 @@ class ConfigParserTestCaseExtendedInterpolation(BasicTestCase, unittest.TestCase with self.assertRaises(exception_class) as cm: cf['interpolated']['$trying'] self.assertEqual(cm.exception.reference, 'dollars:${sick') - self.assertEqual(cm.exception.args[2], '}') #rawval + self.assertEqual(cm.exception.args[2], '${dollars:${sick}}') #rawval def test_case_sensitivity_basic(self): ini = textwrap.dedent(""" diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py index b858509..8718716 100644 --- a/Lib/test/test_deque.py +++ b/Lib/test/test_deque.py @@ -289,6 +289,11 @@ class TestBasic(unittest.TestCase): else: self.assertEqual(d.index(element, start, stop), target) + def test_insert_bug_24913(self): + d = deque('A' * 3) + with self.assertRaises(ValueError): + i = d.index("Hello world", 0, 4) + def test_insert(self): # Test to make sure insert behaves like lists elements = 'ABCDEFGHI' diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index ac211c4..ae929ec 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -1491,6 +1491,24 @@ class TestSingleDispatch(unittest.TestCase): many_abcs = [c.Mapping, c.Sized, c.Callable, c.Container, c.Iterable] self.assertEqual(mro(X, abcs=many_abcs), expected) + def test_false_meta(self): + # see issue23572 + class MetaA(type): + def __len__(self): + return 0 + class A(metaclass=MetaA): + pass + class AA(A): + pass + @functools.singledispatch + def fun(a): + return 'base A' + @fun.register(A) + def _(a): + return 'fun A' + aa = AA() + self.assertEqual(fun(aa), 'fun A') + def test_mro_conflicts(self): c = collections @functools.singledispatch diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py index 7701ad3..ac8d67d 100644 --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -583,8 +583,11 @@ class TestCase(object): finally: result.stopTest(self) return - expecting_failure = getattr(testMethod, - "__unittest_expecting_failure__", False) + expecting_failure_method = getattr(testMethod, + "__unittest_expecting_failure__", False) + expecting_failure_class = getattr(self, + "__unittest_expecting_failure__", False) + expecting_failure = expecting_failure_class or expecting_failure_method outcome = _Outcome(result) try: self._outcome = outcome @@ -1279,8 +1282,10 @@ class TestCase(object): assert expected_regex, "expected_regex must not be empty." expected_regex = re.compile(expected_regex) if not expected_regex.search(text): - msg = msg or "Regex didn't match" - msg = '%s: %r not found in %r' % (msg, expected_regex.pattern, text) + standardMsg = "Regex didn't match: %r not found in %r" % ( + expected_regex.pattern, text) + # _formatMessage ensures the longMessage option is respected + msg = self._formatMessage(msg, standardMsg) raise self.failureException(msg) def assertNotRegex(self, text, unexpected_regex, msg=None): @@ -1289,11 +1294,12 @@ class TestCase(object): unexpected_regex = re.compile(unexpected_regex) match = unexpected_regex.search(text) if match: - msg = msg or "Regex matched" - msg = '%s: %r matches %r in %r' % (msg, - text[match.start():match.end()], - unexpected_regex.pattern, - text) + standardMsg = 'Regex matched: %r matches %r in %r' % ( + text[match.start() : match.end()], + unexpected_regex.pattern, + text) + # _formatMessage ensures the longMessage option is respected + msg = self._formatMessage(msg, standardMsg) raise self.failureException(msg) @@ -1315,6 +1321,7 @@ class TestCase(object): failIf = _deprecate(assertFalse) assertRaisesRegexp = _deprecate(assertRaisesRegex) assertRegexpMatches = _deprecate(assertRegex) + assertNotRegexpMatches = _deprecate(assertNotRegex) diff --git a/Lib/unittest/test/test_assertions.py b/Lib/unittest/test/test_assertions.py index c349a95..e6e2bc2 100644 --- a/Lib/unittest/test/test_assertions.py +++ b/Lib/unittest/test/test_assertions.py @@ -133,7 +133,6 @@ class Test_Assertions(unittest.TestCase): try: self.assertNotRegex('Ala ma kota', r'k.t', 'Message') except self.failureException as e: - self.assertIn("'kot'", e.args[0]) self.assertIn('Message', e.args[0]) else: self.fail('assertNotRegex should have failed.') @@ -329,6 +328,20 @@ class TestLongMessage(unittest.TestCase): "^unexpectedly identical: None$", "^unexpectedly identical: None : oops$"]) + def testAssertRegex(self): + self.assertMessages('assertRegex', ('foo', 'bar'), + ["^Regex didn't match:", + "^oops$", + "^Regex didn't match:", + "^Regex didn't match: (.*) : oops$"]) + + def testAssertNotRegex(self): + self.assertMessages('assertNotRegex', ('foo', 'foo'), + ["^Regex matched:", + "^oops$", + "^Regex matched:", + "^Regex matched: (.*) : oops$"]) + def assertMessagesCM(self, methodName, args, func, errors): """ diff --git a/Lib/unittest/test/test_skipping.py b/Lib/unittest/test/test_skipping.py index 807510f..71f7b70 100644 --- a/Lib/unittest/test/test_skipping.py +++ b/Lib/unittest/test/test_skipping.py @@ -120,6 +120,39 @@ class Test_TestSkipping(unittest.TestCase): self.assertEqual(result.expectedFailures[0][0], test) self.assertTrue(result.wasSuccessful()) + def test_expected_failure_with_wrapped_class(self): + @unittest.expectedFailure + class Foo(unittest.TestCase): + def test_1(self): + self.assertTrue(False) + + events = [] + result = LoggingResult(events) + test = Foo("test_1") + test.run(result) + self.assertEqual(events, + ['startTest', 'addExpectedFailure', 'stopTest']) + self.assertEqual(result.expectedFailures[0][0], test) + self.assertTrue(result.wasSuccessful()) + + def test_expected_failure_with_wrapped_subclass(self): + class Foo(unittest.TestCase): + def test_1(self): + self.assertTrue(False) + + @unittest.expectedFailure + class Bar(Foo): + pass + + events = [] + result = LoggingResult(events) + test = Bar("test_1") + test.run(result) + self.assertEqual(events, + ['startTest', 'addExpectedFailure', 'stopTest']) + self.assertEqual(result.expectedFailures[0][0], test) + self.assertTrue(result.wasSuccessful()) + def test_expected_failure_subtests(self): # A failure in any subtest counts as the expected failure of the # whole test. |
