summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'Lib')
-rw-r--r--Lib/DocXMLRPCServer.py4
-rw-r--r--Lib/SimpleXMLRPCServer.py34
-rw-r--r--Lib/aifc.py2
-rwxr-xr-xLib/base64.py4
-rw-r--r--Lib/doctest.py30
-rw-r--r--Lib/functools.py26
-rw-r--r--Lib/optparse.py5
-rw-r--r--Lib/pprint.py2
-rw-r--r--Lib/pyclbr.py6
-rw-r--r--Lib/test/crashers/dictresize_attack.py32
-rw-r--r--Lib/test/output/test_exceptions52
-rw-r--r--Lib/test/output/test_operations19
-rwxr-xr-xLib/test/regrtest.py3
-rw-r--r--Lib/test/string_tests.py24
-rw-r--r--Lib/test/test_csv.py5
-rw-r--r--Lib/test/test_doctest.py54
-rw-r--r--Lib/test/test_doctest4.txt17
-rw-r--r--Lib/test/test_exceptions.py597
-rw-r--r--Lib/test/test_functools.py (renamed from Lib/test/test_functional.py)6
-rw-r--r--Lib/test/test_itertools.py2
-rw-r--r--Lib/test/test_operations.py56
-rw-r--r--Lib/test/test_optparse.py8
-rw-r--r--Lib/test/test_pprint.py35
-rw-r--r--Lib/test/test_repr.py3
-rw-r--r--Lib/test/test_struct.py219
-rw-r--r--Lib/test/test_urllib2.py116
-rw-r--r--Lib/test/test_weakref.py4
-rw-r--r--Lib/urllib2.py53
28 files changed, 866 insertions, 552 deletions
diff --git a/Lib/DocXMLRPCServer.py b/Lib/DocXMLRPCServer.py
index 259fb18..86ed32b 100644
--- a/Lib/DocXMLRPCServer.py
+++ b/Lib/DocXMLRPCServer.py
@@ -227,6 +227,10 @@ class DocXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
Interpret all HTTP GET requests as requests for server
documentation.
"""
+ # Check that the path is legal
+ if not self.is_rpc_path_valid():
+ self.report_404()
+ return
response = self.server.generate_html_documentation()
self.send_response(200)
diff --git a/Lib/SimpleXMLRPCServer.py b/Lib/SimpleXMLRPCServer.py
index 1d4f00f..0846a68 100644
--- a/Lib/SimpleXMLRPCServer.py
+++ b/Lib/SimpleXMLRPCServer.py
@@ -247,10 +247,10 @@ class SimpleXMLRPCDispatcher:
of changing method dispatch behavior.
"""
- params, method = xmlrpclib.loads(data)
-
- # generate response
try:
+ params, method = xmlrpclib.loads(data)
+
+ # generate response
if dispatch_method is not None:
response = dispatch_method(method, params)
else:
@@ -423,6 +423,17 @@ class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
XML-RPC requests.
"""
+ # Class attribute listing the accessible path components;
+ # paths not on this list will result in a 404 error.
+ rpc_paths = ('/', '/RPC2')
+
+ def is_rpc_path_valid(self):
+ if self.rpc_paths:
+ return self.path in self.rpc_paths
+ else:
+ # If .rpc_paths is empty, just assume all paths are legal
+ return True
+
def do_POST(self):
"""Handles the HTTP POST request.
@@ -430,6 +441,11 @@ class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
which are forwarded to the server's _dispatch method for handling.
"""
+ # Check that the path is legal
+ if not self.is_rpc_path_valid():
+ self.report_404()
+ return
+
try:
# Get arguments by reading body of request.
# We read this in chunks to avoid straining
@@ -468,6 +484,18 @@ class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
self.wfile.flush()
self.connection.shutdown(1)
+ def report_404 (self):
+ # Report a 404 error
+ self.send_response(404)
+ response = 'No such page'
+ self.send_header("Content-type", "text/plain")
+ self.send_header("Content-length", str(len(response)))
+ self.end_headers()
+ self.wfile.write(response)
+ # shut down the connection
+ self.wfile.flush()
+ self.connection.shutdown(1)
+
def log_request(self, code='-', size='-'):
"""Selectively log an accepted request."""
diff --git a/Lib/aifc.py b/Lib/aifc.py
index 781d77c..a5f86be 100644
--- a/Lib/aifc.py
+++ b/Lib/aifc.py
@@ -201,6 +201,8 @@ def _write_long(f, x):
f.write(struct.pack('>L', x))
def _write_string(f, s):
+ if len(s) > 255:
+ raise ValueError("string exceeds maximum pstring length")
f.write(chr(len(s)))
f.write(s)
if len(s) & 1 == 0:
diff --git a/Lib/base64.py b/Lib/base64.py
index 8914acc..c196cd8 100755
--- a/Lib/base64.py
+++ b/Lib/base64.py
@@ -126,7 +126,9 @@ _b32alphabet = {
8: 'I', 17: 'R', 26: '2',
}
-_b32tab = [v for v in _b32alphabet.values()]
+_b32tab = _b32alphabet.items()
+_b32tab.sort()
+_b32tab = [v for k, v in _b32tab]
_b32rev = dict([(v, long(k)) for k, v in _b32alphabet.items()])
diff --git a/Lib/doctest.py b/Lib/doctest.py
index 857bc1a..d549163 100644
--- a/Lib/doctest.py
+++ b/Lib/doctest.py
@@ -1056,12 +1056,13 @@ class DocTestRunner:
>>> tests = DocTestFinder().find(_TestClass)
>>> runner = DocTestRunner(verbose=False)
+ >>> tests.sort(key = lambda test: test.name)
>>> for test in tests:
- ... print runner.run(test)
- (0, 2)
- (0, 1)
- (0, 2)
- (0, 2)
+ ... print test.name, '->', runner.run(test)
+ _TestClass -> (0, 2)
+ _TestClass.__init__ -> (0, 2)
+ _TestClass.get -> (0, 2)
+ _TestClass.square -> (0, 1)
The `summarize` method prints a summary of all the test cases that
have been run by the runner, and returns an aggregated `(f, t)`
@@ -1869,7 +1870,8 @@ def testmod(m=None, name=None, globs=None, verbose=None, isprivate=None,
def testfile(filename, module_relative=True, name=None, package=None,
globs=None, verbose=None, report=True, optionflags=0,
- extraglobs=None, raise_on_error=False, parser=DocTestParser()):
+ extraglobs=None, raise_on_error=False, parser=DocTestParser(),
+ encoding=None):
"""
Test examples in the given file. Return (#failures, #tests).
@@ -1935,6 +1937,9 @@ def testfile(filename, module_relative=True, name=None, package=None,
Optional keyword arg "parser" specifies a DocTestParser (or
subclass) that should be used to extract tests from the files.
+ Optional keyword arg "encoding" specifies an encoding that should
+ be used to convert the file to unicode.
+
Advanced tomfoolery: testmod runs methods of a local instance of
class doctest.Tester, then merges the results into (or creates)
global Tester instance doctest.master. Methods of doctest.master
@@ -1969,6 +1974,9 @@ def testfile(filename, module_relative=True, name=None, package=None,
else:
runner = DocTestRunner(verbose=verbose, optionflags=optionflags)
+ if encoding is not None:
+ text = text.decode(encoding)
+
# Read the file, convert it to a test, and run it.
test = parser.get_doctest(text, globs, name, filename, 0)
runner.run(test)
@@ -2339,7 +2347,8 @@ class DocFileCase(DocTestCase):
)
def DocFileTest(path, module_relative=True, package=None,
- globs=None, parser=DocTestParser(), **options):
+ globs=None, parser=DocTestParser(),
+ encoding=None, **options):
if globs is None:
globs = {}
else:
@@ -2358,6 +2367,10 @@ def DocFileTest(path, module_relative=True, package=None,
# Find the file and read it.
name = os.path.basename(path)
+ # If an encoding is specified, use it to convert the file to unicode
+ if encoding is not None:
+ doc = doc.decode(encoding)
+
# Convert it to a test, and wrap it in a DocFileCase.
test = parser.get_doctest(doc, globs, name, path, 0)
return DocFileCase(test, **options)
@@ -2414,6 +2427,9 @@ def DocFileSuite(*paths, **kw):
parser
A DocTestParser (or subclass) that should be used to extract
tests from the files.
+
+ encoding
+ An encoding that will be used to convert the files to unicode.
"""
suite = unittest.TestSuite()
diff --git a/Lib/functools.py b/Lib/functools.py
new file mode 100644
index 0000000..4935c9f
--- /dev/null
+++ b/Lib/functools.py
@@ -0,0 +1,26 @@
+"""functools.py - Tools for working with functions
+"""
+# Python module wrapper for _functools C module
+# to allow utilities written in Python to be added
+# to the functools module.
+# Written by Nick Coghlan <ncoghlan at gmail.com>
+# Copyright (c) 2006 Python Software Foundation.
+
+from _functools import partial
+__all__ = [
+ "partial",
+]
+
+# Still to come here (need to write tests and docs):
+# update_wrapper - utility function to transfer basic function
+# metadata to wrapper functions
+# WRAPPER_ASSIGNMENTS & WRAPPER_UPDATES - defaults args to above
+# (update_wrapper has been approved by BDFL)
+# wraps - decorator factory equivalent to:
+# def wraps(f):
+# return partial(update_wrapper, wrapped=f)
+#
+# The wraps function makes it easy to avoid the bug that afflicts the
+# decorator example in the python-dev email proposing the
+# update_wrapper function:
+# http://mail.python.org/pipermail/python-dev/2006-May/064775.html
diff --git a/Lib/optparse.py b/Lib/optparse.py
index 9ac987e..6b8f5d1 100644
--- a/Lib/optparse.py
+++ b/Lib/optparse.py
@@ -611,8 +611,10 @@ class Option:
else:
setattr(self, attr, None)
if attrs:
+ attrs = attrs.keys()
+ attrs.sort()
raise OptionError(
- "invalid keyword arguments: %s" % ", ".join(attrs.keys()),
+ "invalid keyword arguments: %s" % ", ".join(attrs),
self)
@@ -1661,6 +1663,7 @@ def _match_abbrev(s, wordmap):
raise BadOptionError(s)
else:
# More than one possible completion: ambiguous prefix.
+ possibilities.sort()
raise AmbiguousOptionError(s, possibilities)
diff --git a/Lib/pprint.py b/Lib/pprint.py
index f77a0e2..19a3dc2 100644
--- a/Lib/pprint.py
+++ b/Lib/pprint.py
@@ -246,7 +246,7 @@ def _safe_repr(object, context, maxlevels, level):
append = components.append
level += 1
saferepr = _safe_repr
- for k, v in object.iteritems():
+ for k, v in sorted(object.items()):
krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
append("%s: %s" % (krepr, vrepr))
diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py
index 0812e22..0731224 100644
--- a/Lib/pyclbr.py
+++ b/Lib/pyclbr.py
@@ -42,7 +42,7 @@ Instances of this class have the following instance variables:
import sys
import imp
import tokenize # Python tokenizer
-from token import NAME, DEDENT, NEWLINE
+from token import NAME, DEDENT, NEWLINE, OP
from operator import itemgetter
__all__ = ["readmodule", "readmodule_ex", "Class", "Function"]
@@ -219,8 +219,10 @@ def _readmodule(module, path, inpackage=None):
break
elif token == ',' and level == 1:
pass
- else:
+ # only use NAME and OP (== dot) tokens for type name
+ elif tokentype in (NAME, OP) and level == 1:
super.append(token)
+ # expressions in the base list are not supported
inherit = names
cur_class = Class(fullmodule, class_name, inherit, file, lineno)
if not stack:
diff --git a/Lib/test/crashers/dictresize_attack.py b/Lib/test/crashers/dictresize_attack.py
deleted file mode 100644
index 1895791..0000000
--- a/Lib/test/crashers/dictresize_attack.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# http://www.python.org/sf/1456209
-
-# A dictresize() attack. If oldtable == mp->ma_smalltable then pure
-# Python code can mangle with mp->ma_smalltable while it is being walked
-# over.
-
-class X(object):
-
- def __hash__(self):
- return 5
-
- def __eq__(self, other):
- if resizing:
- d.clear()
- return False
-
-
-d = {}
-
-resizing = False
-
-d[X()] = 1
-d[X()] = 2
-d[X()] = 3
-d[X()] = 4
-d[X()] = 5
-
-# now trigger a resize
-resizing = True
-d[9] = 6
-
-# ^^^ I get Segmentation fault or Illegal instruction here.
diff --git a/Lib/test/output/test_exceptions b/Lib/test/output/test_exceptions
deleted file mode 100644
index 28a7aa8..0000000
--- a/Lib/test/output/test_exceptions
+++ /dev/null
@@ -1,52 +0,0 @@
-test_exceptions
-5. Built-in exceptions
-spam
-AttributeError
-spam
-EOFError
-spam
-IOError
-spam
-ImportError
-spam
-IndexError
-'spam'
-KeyError
-spam
-KeyboardInterrupt
-(not testable in a script)
-spam
-MemoryError
-(not safe to test)
-spam
-NameError
-spam
-OverflowError
-spam
-RuntimeError
-(not used any more?)
-spam
-SyntaxError
-'continue' not supported inside 'finally' clause
-ok
-'continue' not properly in loop
-ok
-'continue' not properly in loop
-ok
-spam
-IndentationError
-spam
-TabError
-spam
-SystemError
-(hard to reproduce)
-spam
-SystemExit
-spam
-TypeError
-spam
-ValueError
-spam
-ZeroDivisionError
-spam
-Exception
diff --git a/Lib/test/output/test_operations b/Lib/test/output/test_operations
index 32eff3f..8a1bc2a 100644
--- a/Lib/test/output/test_operations
+++ b/Lib/test/output/test_operations
@@ -1,6 +1,21 @@
test_operations
3. Operations
XXX Mostly not yet implemented
-3.1 Dictionary lookups succeed even if __cmp__() raises an exception
+3.1 Dictionary lookups fail if __cmp__() raises an exception
raising error
-No exception passed through.
+d[x2] = 2: caught the RuntimeError outside
+raising error
+z = d[x2]: caught the RuntimeError outside
+raising error
+x2 in d: caught the RuntimeError outside
+raising error
+d.has_key(x2): caught the RuntimeError outside
+raising error
+d.get(x2): caught the RuntimeError outside
+raising error
+d.setdefault(x2, 42): caught the RuntimeError outside
+raising error
+d.pop(x2): caught the RuntimeError outside
+raising error
+d.update({x2: 2}): caught the RuntimeError outside
+resize bugs not triggered.
diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py
index 86961b0..314e7e1 100755
--- a/Lib/test/regrtest.py
+++ b/Lib/test/regrtest.py
@@ -513,6 +513,9 @@ def runtest(test, generate, verbose, quiet, testdir=None, huntrleaks=False):
else:
cfp = cStringIO.StringIO()
if huntrleaks:
+ if not hasattr(sys, 'gettotalrefcount'):
+ raise Exception("Tracking reference leaks requires a debug build "
+ "of Python")
refrep = open(huntrleaks[2], "a")
try:
save_stdout = sys.stdout
diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py
index 489af20..aaa2dc2 100644
--- a/Lib/test/string_tests.py
+++ b/Lib/test/string_tests.py
@@ -106,10 +106,19 @@ class CommonTest(unittest.TestCase):
self.checkequal(3, 'aaa', 'count', 'a')
self.checkequal(0, 'aaa', 'count', 'b')
self.checkequal(0, 'aaa', 'count', 'b')
+ self.checkequal(2, 'aaa', 'count', 'a', 1)
+ self.checkequal(0, 'aaa', 'count', 'a', 10)
self.checkequal(1, 'aaa', 'count', 'a', -1)
self.checkequal(3, 'aaa', 'count', 'a', -10)
+ self.checkequal(1, 'aaa', 'count', 'a', 0, 1)
+ self.checkequal(3, 'aaa', 'count', 'a', 0, 10)
self.checkequal(2, 'aaa', 'count', 'a', 0, -1)
self.checkequal(0, 'aaa', 'count', 'a', 0, -10)
+ self.checkequal(3, 'aaa', 'count', '', 1)
+ self.checkequal(1, 'aaa', 'count', '', 3)
+ self.checkequal(0, 'aaa', 'count', '', 10)
+ self.checkequal(2, 'aaa', 'count', '', -1)
+ self.checkequal(4, 'aaa', 'count', '', -10)
self.checkraises(TypeError, 'hello', 'count')
self.checkraises(TypeError, 'hello', 'count', 42)
@@ -146,6 +155,10 @@ class CommonTest(unittest.TestCase):
self.checkequal(9, 'abcdefghiabc', 'find', 'abc', 1)
self.checkequal(-1, 'abcdefghiabc', 'find', 'def', 4)
+ self.checkequal(0, 'abc', 'find', '', 0)
+ self.checkequal(3, 'abc', 'find', '', 3)
+ self.checkequal(-1, 'abc', 'find', '', 4)
+
self.checkraises(TypeError, 'hello', 'find')
self.checkraises(TypeError, 'hello', 'find', 42)
@@ -180,6 +193,10 @@ class CommonTest(unittest.TestCase):
self.checkequal(0, 'abcdefghiabc', 'rfind', 'abcd')
self.checkequal(-1, 'abcdefghiabc', 'rfind', 'abcz')
+ self.checkequal(3, 'abc', 'rfind', '', 0)
+ self.checkequal(3, 'abc', 'rfind', '', 3)
+ self.checkequal(-1, 'abc', 'rfind', '', 4)
+
self.checkraises(TypeError, 'hello', 'rfind')
self.checkraises(TypeError, 'hello', 'rfind', 42)
@@ -477,12 +494,7 @@ class CommonTest(unittest.TestCase):
# Operations on the empty string
EQ("", "", "replace", "", "")
-
- #EQ("A", "", "replace", "", "A")
- # That was the correct result; this is the result we actually get
- # now (for str, but not for unicode):
- #EQ("", "", "replace", "", "A")
-
+ EQ("A", "", "replace", "", "A")
EQ("", "", "replace", "A", "")
EQ("", "", "replace", "A", "A")
EQ("", "", "replace", "", "", 100)
diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py
index 8511a5a..feb6ddf 100644
--- a/Lib/test/test_csv.py
+++ b/Lib/test/test_csv.py
@@ -875,7 +875,10 @@ Stonecutters Seafood and Chop House, Lemont, IL, 12/19/02, Week Back
def test_delimiters(self):
sniffer = csv.Sniffer()
dialect = sniffer.sniff(self.sample3)
- self.assertEqual(dialect.delimiter, "0")
+ # given that all three lines in sample3 are equal,
+ # I think that any character could have been 'guessed' as the
+ # delimiter, depending on dictionary order
+ self.assert_(dialect.delimiter in self.sample3)
dialect = sniffer.sniff(self.sample3, delimiters="?,")
self.assertEqual(dialect.delimiter, "?")
dialect = sniffer.sniff(self.sample3, delimiters="/,")
diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py
index 443c962..92d2d74 100644
--- a/Lib/test/test_doctest.py
+++ b/Lib/test/test_doctest.py
@@ -1937,9 +1937,10 @@ def test_DocFileSuite():
>>> import unittest
>>> suite = doctest.DocFileSuite('test_doctest.txt',
- ... 'test_doctest2.txt')
+ ... 'test_doctest2.txt',
+ ... 'test_doctest4.txt')
>>> suite.run(unittest.TestResult())
- <unittest.TestResult run=2 errors=0 failures=2>
+ <unittest.TestResult run=3 errors=0 failures=3>
The test files are looked for in the directory containing the
calling module. A package keyword argument can be provided to
@@ -1948,9 +1949,10 @@ def test_DocFileSuite():
>>> import unittest
>>> suite = doctest.DocFileSuite('test_doctest.txt',
... 'test_doctest2.txt',
+ ... 'test_doctest4.txt',
... package='test')
>>> suite.run(unittest.TestResult())
- <unittest.TestResult run=2 errors=0 failures=2>
+ <unittest.TestResult run=3 errors=0 failures=3>
'/' should be used as a path separator. It will be converted
to a native separator at run time:
@@ -1995,19 +1997,21 @@ def test_DocFileSuite():
>>> suite = doctest.DocFileSuite('test_doctest.txt',
... 'test_doctest2.txt',
+ ... 'test_doctest4.txt',
... globs={'favorite_color': 'blue'})
>>> suite.run(unittest.TestResult())
- <unittest.TestResult run=2 errors=0 failures=1>
+ <unittest.TestResult run=3 errors=0 failures=2>
In this case, we supplied a missing favorite color. You can
provide doctest options:
>>> suite = doctest.DocFileSuite('test_doctest.txt',
... 'test_doctest2.txt',
+ ... 'test_doctest4.txt',
... optionflags=doctest.DONT_ACCEPT_BLANKLINE,
... globs={'favorite_color': 'blue'})
>>> suite.run(unittest.TestResult())
- <unittest.TestResult run=2 errors=0 failures=2>
+ <unittest.TestResult run=3 errors=0 failures=3>
And, you can provide setUp and tearDown functions:
@@ -2025,9 +2029,10 @@ def test_DocFileSuite():
>>> suite = doctest.DocFileSuite('test_doctest.txt',
... 'test_doctest2.txt',
+ ... 'test_doctest4.txt',
... setUp=setUp, tearDown=tearDown)
>>> suite.run(unittest.TestResult())
- <unittest.TestResult run=2 errors=0 failures=1>
+ <unittest.TestResult run=3 errors=0 failures=2>
But the tearDown restores sanity:
@@ -2060,6 +2065,17 @@ def test_DocFileSuite():
>>> suite.run(unittest.TestResult())
<unittest.TestResult run=1 errors=0 failures=0>
+ If the tests contain non-ASCII characters, we have to specify which
+ encoding the file is encoded with. We do so by using the `encoding`
+ parameter:
+
+ >>> suite = doctest.DocFileSuite('test_doctest.txt',
+ ... 'test_doctest2.txt',
+ ... 'test_doctest4.txt',
+ ... encoding='utf-8')
+ >>> suite.run(unittest.TestResult())
+ <unittest.TestResult run=3 errors=0 failures=2>
+
"""
def test_trailing_space_in_test():
@@ -2266,6 +2282,32 @@ debugging):
Traceback (most recent call last):
UnexpectedException: ...
>>> doctest.master = None # Reset master.
+
+If the tests contain non-ASCII characters, the tests might fail, since
+it's unknown which encoding is used. The encoding can be specified
+using the optional keyword argument `encoding`:
+
+ >>> doctest.testfile('test_doctest4.txt') # doctest: +ELLIPSIS
+ **********************************************************************
+ File "...", line 7, in test_doctest4.txt
+ Failed example:
+ u'...'
+ Expected:
+ u'f\xf6\xf6'
+ Got:
+ u'f\xc3\xb6\xc3\xb6'
+ **********************************************************************
+ ...
+ **********************************************************************
+ 1 items had failures:
+ 2 of 4 in test_doctest4.txt
+ ***Test Failed*** 2 failures.
+ (2, 4)
+ >>> doctest.master = None # Reset master.
+
+ >>> doctest.testfile('test_doctest4.txt', encoding='utf-8')
+ (0, 4)
+ >>> doctest.master = None # Reset master.
"""
# old_test1, ... used to live in doctest.py, but cluttered it. Note
diff --git a/Lib/test/test_doctest4.txt b/Lib/test/test_doctest4.txt
new file mode 100644
index 0000000..a219d16
--- /dev/null
+++ b/Lib/test/test_doctest4.txt
@@ -0,0 +1,17 @@
+This is a sample doctest in a text file that contains non-ASCII characters.
+This file is encoded using UTF-8.
+
+In order to get this test to pass, we have to manually specify the
+encoding.
+
+ >>> u'föö'
+ u'f\xf6\xf6'
+
+ >>> u'bąr'
+ u'b\u0105r'
+
+ >>> 'föö'
+ 'f\xc3\xb6\xc3\xb6'
+
+ >>> 'bąr'
+ 'b\xc4\x85r'
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
index 8f995f7..ebab913 100644
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -1,303 +1,310 @@
# Python test set -- part 5, built-in exceptions
-from test.test_support import TestFailed, TESTFN, unlink
-from types import ClassType
+from test.test_support import TESTFN, unlink, run_unittest
import warnings
import sys, traceback, os
+import unittest
-print '5. Built-in exceptions'
# XXX This is not really enough, each *operation* should be tested!
-# Reloading the built-in exceptions module failed prior to Py2.2, while it
-# should act the same as reloading built-in sys.
-try:
- import exceptions
- reload(exceptions)
-except ImportError, e:
- raise TestFailed, e
-
-def test_raise_catch(exc):
- try:
- raise exc, "spam"
- except exc, err:
- buf = str(err)
- try:
- raise exc("spam")
- except exc, err:
- buf = str(err)
- print buf
-
-def r(thing):
- test_raise_catch(thing)
- print getattr(thing, '__name__', thing)
-
-r(AttributeError)
-import sys
-try: x = sys.undefined_attribute
-except AttributeError: pass
-
-r(EOFError)
-import sys
-fp = open(TESTFN, 'w')
-fp.close()
-fp = open(TESTFN, 'r')
-savestdin = sys.stdin
-try:
- try:
- import marshal
- marshal.loads('')
- except EOFError:
- pass
-finally:
- sys.stdin = savestdin
- fp.close()
-
-r(IOError)
-try: open('this file does not exist', 'r')
-except IOError: pass
-
-r(ImportError)
-try: import undefined_module
-except ImportError: pass
-
-r(IndexError)
-x = []
-try: a = x[10]
-except IndexError: pass
-
-r(KeyError)
-x = {}
-try: a = x['key']
-except KeyError: pass
-
-r(KeyboardInterrupt)
-print '(not testable in a script)'
-
-r(MemoryError)
-print '(not safe to test)'
-
-r(NameError)
-try: x = undefined_variable
-except NameError: pass
-
-r(OverflowError)
-x = 1
-for dummy in range(128):
- x += x # this simply shouldn't blow up
-
-r(RuntimeError)
-print '(not used any more?)'
-
-r(SyntaxError)
-try: exec '/\n'
-except SyntaxError: pass
-
-# make sure the right exception message is raised for each of these
-# code fragments:
-
-def ckmsg(src, msg):
- try:
- compile(src, '<fragment>', 'exec')
- except SyntaxError, e:
- print e.msg
- if e.msg == msg:
- print "ok"
- else:
- print "expected:", msg
- else:
- print "failed to get expected SyntaxError"
-
-s = '''\
-while 1:
- try:
- pass
- finally:
- continue
-'''
-if sys.platform.startswith('java'):
- print "'continue' not supported inside 'finally' clause"
- print "ok"
-else:
- ckmsg(s, "'continue' not supported inside 'finally' clause")
-s = '''\
-try:
- continue
-except:
- pass
-'''
-ckmsg(s, "'continue' not properly in loop")
-ckmsg("continue\n", "'continue' not properly in loop")
-
-r(IndentationError)
-
-r(TabError)
-# can only be tested under -tt, and is the only test for -tt
-#try: compile("try:\n\t1/0\n \t1/0\nfinally:\n pass\n", '<string>', 'exec')
-#except TabError: pass
-#else: raise TestFailed
-
-r(SystemError)
-print '(hard to reproduce)'
-
-r(SystemExit)
-import sys
-try: sys.exit(0)
-except SystemExit: pass
-
-r(TypeError)
-try: [] + ()
-except TypeError: pass
-
-r(ValueError)
-try: x = chr(10000)
-except ValueError: pass
-
-r(ZeroDivisionError)
-try: x = 1/0
-except ZeroDivisionError: pass
-
-r(Exception)
-try: x = 1/0
-except Exception, e: pass
-
-# test that setting an exception at the C level works even if the
-# exception object can't be constructed.
-
-class BadException(Exception):
- def __init__(self):
- raise RuntimeError, "can't instantiate BadException"
-
-# Exceptions must inherit from BaseException, raising invalid exception
-# should instead raise SystemError
-class InvalidException:
- pass
-
-def test_capi1():
- import _testcapi
- try:
- _testcapi.raise_exception(BadException, 1)
- except TypeError, err:
- exc, err, tb = sys.exc_info()
- co = tb.tb_frame.f_code
- assert co.co_name == "test_capi1"
- assert co.co_filename.endswith('test_exceptions'+os.extsep+'py')
- else:
- print "Expected exception"
-
-def test_capi2():
- import _testcapi
- try:
- _testcapi.raise_exception(BadException, 0)
- except RuntimeError, err:
- exc, err, tb = sys.exc_info()
- co = tb.tb_frame.f_code
- assert co.co_name == "__init__"
- assert co.co_filename.endswith('test_exceptions'+os.extsep+'py')
- co2 = tb.tb_frame.f_back.f_code
- assert co2.co_name == "test_capi2"
- else:
- print "Expected exception"
-
-def test_capi3():
- import _testcapi
- try:
- _testcapi.raise_exception(InvalidException, 1)
- except SystemError:
- pass
- except InvalidException:
- raise AssertionError("Managed to raise InvalidException");
- else:
- print "Expected SystemError exception"
-
-
-if not sys.platform.startswith('java'):
- test_capi1()
- test_capi2()
- test_capi3()
-
-unlink(TESTFN)
-
-# test that exception attributes are happy.
-try: str(u'Hello \u00E1')
-except Exception, e: sampleUnicodeEncodeError = e
-try: unicode('\xff')
-except Exception, e: sampleUnicodeDecodeError = e
-exceptionList = [
- ( BaseException, (), { 'message' : '', 'args' : () }),
- ( BaseException, (1, ), { 'message' : 1, 'args' : ( 1, ) }),
- ( BaseException, ('foo', ), { 'message' : 'foo', 'args' : ( 'foo', ) }),
- ( BaseException, ('foo', 1), { 'message' : '', 'args' : ( 'foo', 1 ) }),
- ( SystemExit, ('foo',), { 'message' : 'foo', 'args' : ( 'foo', ),
- 'code' : 'foo' }),
- ( IOError, ('foo',), { 'message' : 'foo', 'args' : ( 'foo', ), }),
- ( IOError, ('foo', 'bar'), { 'message' : '',
- 'args' : ('foo', 'bar'), }),
- ( IOError, ('foo', 'bar', 'baz'),
- { 'message' : '', 'args' : ('foo', 'bar'), }),
- ( EnvironmentError, ('errnoStr', 'strErrorStr', 'filenameStr'),
- { 'message' : '', 'args' : ('errnoStr', 'strErrorStr'),
- 'strerror' : 'strErrorStr',
- 'errno' : 'errnoStr', 'filename' : 'filenameStr' }),
- ( EnvironmentError, (1, 'strErrorStr', 'filenameStr'),
- { 'message' : '', 'args' : (1, 'strErrorStr'),
- 'strerror' : 'strErrorStr', 'errno' : 1,
- 'filename' : 'filenameStr' }),
- ( SyntaxError, ('msgStr',),
- { 'message' : 'msgStr', 'args' : ('msgStr', ),
- 'print_file_and_line' : None, 'msg' : 'msgStr',
- 'filename' : None, 'lineno' : None, 'offset' : None,
- 'text' : None }),
- ( SyntaxError, ('msgStr', ('filenameStr', 'linenoStr', 'offsetStr',
- 'textStr')),
- { 'message' : '', 'args' : ('msgStr', ('filenameStr',
- 'linenoStr', 'offsetStr', 'textStr' )),
- 'print_file_and_line' : None, 'msg' : 'msgStr',
- 'filename' : 'filenameStr', 'lineno' : 'linenoStr',
- 'offset' : 'offsetStr', 'text' : 'textStr' }),
- ( SyntaxError, ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
- 'textStr', 'print_file_and_lineStr'),
- { 'message' : '', 'args' : ('msgStr', 'filenameStr',
- 'linenoStr', 'offsetStr', 'textStr',
- 'print_file_and_lineStr'),
- 'print_file_and_line' : None, 'msg' : 'msgStr',
- 'filename' : None, 'lineno' : None, 'offset' : None,
- 'text' : None }),
- ( UnicodeError, (),
- { 'message' : '', 'args' : (), }),
- ( sampleUnicodeEncodeError,
- { 'message' : '', 'args' : ('ascii', u'Hello \xe1', 6, 7,
- 'ordinal not in range(128)'),
- 'encoding' : 'ascii', 'object' : u'Hello \xe1',
- 'start' : 6, 'reason' : 'ordinal not in range(128)' }),
- ( sampleUnicodeDecodeError,
- { 'message' : '', 'args' : ('ascii', '\xff', 0, 1,
- 'ordinal not in range(128)'),
- 'encoding' : 'ascii', 'object' : '\xff',
- 'start' : 0, 'reason' : 'ordinal not in range(128)' }),
- ( UnicodeTranslateError, (u"\u3042", 0, 1, "ouch"),
- { 'message' : '', 'args' : (u'\u3042', 0, 1, 'ouch'),
- 'object' : u'\u3042', 'reason' : 'ouch',
- 'start' : 0, 'end' : 1 }),
+class ExceptionTests(unittest.TestCase):
+
+ def testReload(self):
+ # Reloading the built-in exceptions module failed prior to Py2.2, while it
+ # should act the same as reloading built-in sys.
+ try:
+ import exceptions
+ reload(exceptions)
+ except ImportError, e:
+ self.fail("reloading exceptions: %s" % e)
+
+ def raise_catch(self, exc, excname):
+ try:
+ raise exc, "spam"
+ except exc, err:
+ buf1 = str(err)
+ try:
+ raise exc("spam")
+ except exc, err:
+ buf2 = str(err)
+ self.assertEquals(buf1, buf2)
+ self.assertEquals(exc.__name__, excname)
+
+ def testRaising(self):
+ self.raise_catch(AttributeError, "AttributeError")
+ self.assertRaises(AttributeError, getattr, sys, "undefined_attribute")
+
+ self.raise_catch(EOFError, "EOFError")
+ fp = open(TESTFN, 'w')
+ fp.close()
+ fp = open(TESTFN, 'r')
+ savestdin = sys.stdin
+ try:
+ try:
+ import marshal
+ marshal.loads('')
+ except EOFError:
+ pass
+ finally:
+ sys.stdin = savestdin
+ fp.close()
+ unlink(TESTFN)
+
+ self.raise_catch(IOError, "IOError")
+ self.assertRaises(IOError, open, 'this file does not exist', 'r')
+
+ self.raise_catch(ImportError, "ImportError")
+ self.assertRaises(ImportError, __import__, "undefined_module")
+
+ self.raise_catch(IndexError, "IndexError")
+ x = []
+ self.assertRaises(IndexError, x.__getitem__, 10)
+
+ self.raise_catch(KeyError, "KeyError")
+ x = {}
+ self.assertRaises(KeyError, x.__getitem__, 'key')
+
+ self.raise_catch(KeyboardInterrupt, "KeyboardInterrupt")
+
+ self.raise_catch(MemoryError, "MemoryError")
+
+ self.raise_catch(NameError, "NameError")
+ try: x = undefined_variable
+ except NameError: pass
+
+ self.raise_catch(OverflowError, "OverflowError")
+ x = 1
+ for dummy in range(128):
+ x += x # this simply shouldn't blow up
+
+ self.raise_catch(RuntimeError, "RuntimeError")
+
+ self.raise_catch(SyntaxError, "SyntaxError")
+ try: exec '/\n'
+ except SyntaxError: pass
+
+ self.raise_catch(IndentationError, "IndentationError")
+
+ self.raise_catch(TabError, "TabError")
+ # can only be tested under -tt, and is the only test for -tt
+ #try: compile("try:\n\t1/0\n \t1/0\nfinally:\n pass\n", '<string>', 'exec')
+ #except TabError: pass
+ #else: self.fail("TabError not raised")
+
+ self.raise_catch(SystemError, "SystemError")
+
+ self.raise_catch(SystemExit, "SystemExit")
+ self.assertRaises(SystemExit, sys.exit, 0)
+
+ self.raise_catch(TypeError, "TypeError")
+ try: [] + ()
+ except TypeError: pass
+
+ self.raise_catch(ValueError, "ValueError")
+ self.assertRaises(ValueError, chr, 10000)
+
+ self.raise_catch(ZeroDivisionError, "ZeroDivisionError")
+ try: x = 1/0
+ except ZeroDivisionError: pass
+
+ self.raise_catch(Exception, "Exception")
+ try: x = 1/0
+ except Exception, e: pass
+
+ def testSyntaxErrorMessage(self):
+ # make sure the right exception message is raised for each of
+ # these code fragments
+
+ def ckmsg(src, msg):
+ try:
+ compile(src, '<fragment>', 'exec')
+ except SyntaxError, e:
+ if e.msg != msg:
+ self.fail("expected %s, got %s" % (msg, e.msg))
+ else:
+ self.fail("failed to get expected SyntaxError")
+
+ s = '''while 1:
+ try:
+ pass
+ finally:
+ continue'''
+
+ if not sys.platform.startswith('java'):
+ ckmsg(s, "'continue' not supported inside 'finally' clause")
+
+ s = '''if 1:
+ try:
+ continue
+ except:
+ pass'''
+
+ ckmsg(s, "'continue' not properly in loop")
+ ckmsg("continue\n", "'continue' not properly in loop")
+
+ def testSettingException(self):
+ # test that setting an exception at the C level works even if the
+ # exception object can't be constructed.
+
+ class BadException(Exception):
+ def __init__(self_):
+ raise RuntimeError, "can't instantiate BadException"
+
+ class InvalidException:
+ pass
+
+ def test_capi1():
+ import _testcapi
+ try:
+ _testcapi.raise_exception(BadException, 1)
+ except TypeError, err:
+ exc, err, tb = sys.exc_info()
+ co = tb.tb_frame.f_code
+ self.assertEquals(co.co_name, "test_capi1")
+ self.assert_(co.co_filename.endswith('test_exceptions'+os.extsep+'py'))
+ else:
+ self.fail("Expected exception")
+
+ def test_capi2():
+ import _testcapi
+ try:
+ _testcapi.raise_exception(BadException, 0)
+ except RuntimeError, err:
+ exc, err, tb = sys.exc_info()
+ co = tb.tb_frame.f_code
+ self.assertEquals(co.co_name, "__init__")
+ self.assert_(co.co_filename.endswith('test_exceptions'+os.extsep+'py'))
+ co2 = tb.tb_frame.f_back.f_code
+ self.assertEquals(co2.co_name, "test_capi2")
+ else:
+ self.fail("Expected exception")
+
+ def test_capi3():
+ import _testcapi
+ self.assertRaises(SystemError, _testcapi.raise_exception,
+ InvalidException, 1)
+
+ if not sys.platform.startswith('java'):
+ test_capi1()
+ test_capi2()
+ test_capi3()
+
+ def testAttributes(self):
+ # test that exception attributes are happy
+ try: str(u'Hello \u00E1')
+ except Exception, e: sampleUnicodeEncodeError = e
+
+ try: unicode('\xff')
+ except Exception, e: sampleUnicodeDecodeError = e
+
+ exceptionList = [
+ (BaseException, (), {'message' : '', 'args' : ()}),
+ (BaseException, (1, ), {'message' : 1, 'args' : (1,)}),
+ (BaseException, ('foo',),
+ {'message' : 'foo', 'args' : ('foo',)}),
+ (BaseException, ('foo', 1),
+ {'message' : '', 'args' : ('foo', 1)}),
+ (SystemExit, ('foo',),
+ {'message' : 'foo', 'args' : ('foo',), 'code' : 'foo'}),
+ (IOError, ('foo',),
+ {'message' : 'foo', 'args' : ('foo',)}),
+ (IOError, ('foo', 'bar'),
+ {'message' : '', 'args' : ('foo', 'bar')}),
+ (IOError, ('foo', 'bar', 'baz'),
+ {'message' : '', 'args' : ('foo', 'bar')}),
+ (EnvironmentError, ('errnoStr', 'strErrorStr', 'filenameStr'),
+ {'message' : '', 'args' : ('errnoStr', 'strErrorStr'),
+ 'strerror' : 'strErrorStr', 'errno' : 'errnoStr',
+ 'filename' : 'filenameStr'}),
+ (EnvironmentError, (1, 'strErrorStr', 'filenameStr'),
+ {'message' : '', 'args' : (1, 'strErrorStr'), 'errno' : 1,
+ 'strerror' : 'strErrorStr', 'filename' : 'filenameStr'}),
+ (SyntaxError, ('msgStr',),
+ {'message' : 'msgStr', 'args' : ('msgStr',), 'text' : None,
+ 'print_file_and_line' : None, 'msg' : 'msgStr',
+ 'filename' : None, 'lineno' : None, 'offset' : None}),
+ (SyntaxError, ('msgStr', ('filenameStr', 'linenoStr', 'offsetStr',
+ 'textStr')),
+ {'message' : '', 'offset' : 'offsetStr', 'text' : 'textStr',
+ 'args' : ('msgStr', ('filenameStr', 'linenoStr',
+ 'offsetStr', 'textStr')),
+ 'print_file_and_line' : None, 'msg' : 'msgStr',
+ 'filename' : 'filenameStr', 'lineno' : 'linenoStr'}),
+ (SyntaxError, ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
+ 'textStr', 'print_file_and_lineStr'),
+ {'message' : '', 'text' : None,
+ 'args' : ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
+ 'textStr', 'print_file_and_lineStr'),
+ 'print_file_and_line' : None, 'msg' : 'msgStr',
+ 'filename' : None, 'lineno' : None, 'offset' : None}),
+ (UnicodeError, (), {'message' : '', 'args' : (),}),
+ (sampleUnicodeEncodeError,
+ {'message' : '', 'args' : ('ascii', u'Hello \xe1', 6, 7,
+ 'ordinal not in range(128)'),
+ 'encoding' : 'ascii', 'object' : u'Hello \xe1',
+ 'start' : 6, 'reason' : 'ordinal not in range(128)'}),
+ (sampleUnicodeDecodeError,
+ {'message' : '', 'args' : ('ascii', '\xff', 0, 1,
+ 'ordinal not in range(128)'),
+ 'encoding' : 'ascii', 'object' : '\xff',
+ 'start' : 0, 'reason' : 'ordinal not in range(128)'}),
+ (UnicodeTranslateError, (u"\u3042", 0, 1, "ouch"),
+ {'message' : '', 'args' : (u'\u3042', 0, 1, 'ouch'),
+ 'object' : u'\u3042', 'reason' : 'ouch',
+ 'start' : 0, 'end' : 1}),
]
-try:
- exceptionList.append(
- ( WindowsError, (1, 'strErrorStr', 'filenameStr'),
- { 'message' : '', 'args' : (1, 'strErrorStr'),
- 'strerror' : 'strErrorStr',
- 'errno' : 22, 'filename' : 'filenameStr',
- 'winerror' : 1 }))
-except NameError: pass
-
-for args in exceptionList:
- expected = args[-1]
- try:
- if len(args) == 2: raise args[0]
- else: raise apply(args[0], args[1])
- except BaseException, e:
- for checkArgName in expected.keys():
- if repr(getattr(e, checkArgName)) != repr(expected[checkArgName]):
- raise TestFailed('Checking exception arguments, exception '
- '"%s", attribute "%s" expected %s got %s.' %
- ( repr(e), checkArgName,
- repr(expected[checkArgName]),
- repr(getattr(e, checkArgName)) ))
+ try:
+ exceptionList.append(
+ (WindowsError, (1, 'strErrorStr', 'filenameStr'),
+ {'message' : '', 'args' : (1, 'strErrorStr'),
+ 'strerror' : 'strErrorStr', 'winerror' : 1,
+ 'errno' : 22, 'filename' : 'filenameStr'})
+ )
+ except NameError: pass
+
+ import pickle, random
+
+ for args in exceptionList:
+ expected = args[-1]
+ try:
+ exc = args[0]
+ if len(args) == 2: raise exc
+ else: raise exc(*args[1])
+ except BaseException, e:
+ if (e is not exc and # needed for sampleUnicode errors
+ type(e) is not exc):
+ raise
+ # Verify no ref leaks in Exc_str()
+ s = str(e)
+ for checkArgName in expected:
+ self.assertEquals(repr(getattr(e, checkArgName)),
+ repr(expected[checkArgName]),
+ 'exception "%s", attribute "%s"' %
+ (repr(e), checkArgName))
+
+ # test for pickling support
+ new = pickle.loads(pickle.dumps(e, random.randint(0, 2)))
+ for checkArgName in expected:
+ self.assertEquals(repr(getattr(e, checkArgName)),
+ repr(expected[checkArgName]),
+ 'pickled exception "%s", attribute "%s' %
+ (repr(e), checkArgName))
+
+ def testKeywordArgs(self):
+ # test that builtin exception don't take keyword args,
+ # but user-defined subclasses can if they want
+ self.assertRaises(TypeError, BaseException, a=1)
+
+ class DerivedException(BaseException):
+ def __init__(self, fancy_arg):
+ BaseException.__init__(self)
+ self.fancy_arg = fancy_arg
+
+ x = DerivedException(fancy_arg=42)
+ self.assertEquals(x.fancy_arg, 42)
+
+def test_main():
+ run_unittest(ExceptionTests)
+
+if __name__ == '__main__':
+ test_main()
diff --git a/Lib/test/test_functional.py b/Lib/test/test_functools.py
index 5078a2e..609e8f4 100644
--- a/Lib/test/test_functional.py
+++ b/Lib/test/test_functools.py
@@ -1,4 +1,4 @@
-import functional
+import functools
import unittest
from test import test_support
from weakref import proxy
@@ -21,7 +21,7 @@ def capture(*args, **kw):
class TestPartial(unittest.TestCase):
- thetype = functional.partial
+ thetype = functools.partial
def test_basic_examples(self):
p = self.thetype(capture, 1, 2, a=10, b=20)
@@ -140,7 +140,7 @@ class TestPartial(unittest.TestCase):
join = self.thetype(''.join)
self.assertEqual(join(data), '0123456789')
-class PartialSubclass(functional.partial):
+class PartialSubclass(functools.partial):
pass
class TestPartialSubclass(TestPartial):
diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py
index c4ed3bc..b2a9b55 100644
--- a/Lib/test/test_itertools.py
+++ b/Lib/test/test_itertools.py
@@ -766,7 +766,7 @@ Samuele
>>> from operator import itemgetter
>>> d = dict(a=1, b=2, c=1, d=2, e=1, f=2, g=3)
->>> di = sorted(d.iteritems(), key=itemgetter(1))
+>>> di = sorted(sorted(d.iteritems()), key=itemgetter(1))
>>> for k, g in groupby(di, itemgetter(1)):
... print k, map(itemgetter(0), g)
...
diff --git a/Lib/test/test_operations.py b/Lib/test/test_operations.py
index b599c9d..fafc062 100644
--- a/Lib/test/test_operations.py
+++ b/Lib/test/test_operations.py
@@ -5,27 +5,16 @@ print '3. Operations'
print 'XXX Mostly not yet implemented'
-print '3.1 Dictionary lookups succeed even if __cmp__() raises an exception'
-
-# SourceForge bug #112558:
-# http://sourceforge.net/bugs/?func=detailbug&bug_id=112558&group_id=5470
+print '3.1 Dictionary lookups fail if __cmp__() raises an exception'
class BadDictKey:
- already_printed_raising_error = 0
def __hash__(self):
return hash(self.__class__)
def __cmp__(self, other):
if isinstance(other, self.__class__):
- if not BadDictKey.already_printed_raising_error:
- # How many times __cmp__ gets called depends on the hash
- # code and the internals of the dict implementation; we
- # know it will be called at least once, but that's it.
- # already_printed_raising_error makes sure the expected-
- # output file prints the msg at most once.
- BadDictKey.already_printed_raising_error = 1
- print "raising error"
+ print "raising error"
raise RuntimeError, "gotcha"
return other
@@ -33,8 +22,21 @@ d = {}
x1 = BadDictKey()
x2 = BadDictKey()
d[x1] = 1
-d[x2] = 2
-print "No exception passed through."
+for stmt in ['d[x2] = 2',
+ 'z = d[x2]',
+ 'x2 in d',
+ 'd.has_key(x2)',
+ 'd.get(x2)',
+ 'd.setdefault(x2, 42)',
+ 'd.pop(x2)',
+ 'd.update({x2: 2})']:
+ try:
+ exec stmt
+ except RuntimeError:
+ print "%s: caught the RuntimeError outside" % (stmt,)
+ else:
+ print "%s: No exception passed through!" # old CPython behavior
+
# Dict resizing bug, found by Jack Jansen in 2.2 CVS development.
# This version got an assert failure in debug build, infinite loop in
@@ -50,3 +52,27 @@ for i in range(5):
del d[i]
for i in range(5, 9): # i==8 was the problem
d[i] = i
+
+
+# Another dict resizing bug (SF bug #1456209).
+# This caused Segmentation faults or Illegal instructions.
+
+class X(object):
+ def __hash__(self):
+ return 5
+ def __eq__(self, other):
+ if resizing:
+ d.clear()
+ return False
+d = {}
+resizing = False
+d[X()] = 1
+d[X()] = 2
+d[X()] = 3
+d[X()] = 4
+d[X()] = 5
+# now trigger a resize
+resizing = True
+d[9] = 6
+
+print 'resize bugs not triggered.'
diff --git a/Lib/test/test_optparse.py b/Lib/test/test_optparse.py
index 991c06d..79df906 100644
--- a/Lib/test/test_optparse.py
+++ b/Lib/test/test_optparse.py
@@ -230,7 +230,7 @@ class TestOptionChecks(BaseTest):
def test_attr_invalid(self):
self.assertOptionError(
- "option -b: invalid keyword arguments: foo, bar",
+ "option -b: invalid keyword arguments: bar, foo",
["-b"], {'foo': None, 'bar': None})
def test_action_invalid(self):
@@ -718,9 +718,8 @@ class TestStandard(BaseTest):
def test_ambiguous_option(self):
self.parser.add_option("--foz", action="store",
type="string", dest="foo")
- possibilities = ", ".join({"--foz": None, "--foo": None}.keys())
self.assertParseFail(["--f=bar"],
- "ambiguous option: --f (%s?)" % possibilities)
+ "ambiguous option: --f (--foo, --foz?)")
def test_short_and_long_option_split(self):
@@ -1537,10 +1536,9 @@ class TestMatchAbbrev(BaseTest):
def test_match_abbrev_error(self):
s = "--f"
wordmap = {"--foz": None, "--foo": None, "--fie": None}
- possibilities = ", ".join(wordmap.keys())
self.assertRaises(
_match_abbrev, (s, wordmap), None,
- BadOptionError, "ambiguous option: --f (%s?)" % possibilities)
+ BadOptionError, "ambiguous option: --f (--fie, --foo, --foz?)")
class TestParseNumber(BaseTest):
diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py
index 27d6b52..09ba268 100644
--- a/Lib/test/test_pprint.py
+++ b/Lib/test/test_pprint.py
@@ -11,16 +11,21 @@ except NameError:
# list, tuple and dict subclasses that do or don't overwrite __repr__
class list2(list):
pass
+
class list3(list):
def __repr__(self):
return list.__repr__(self)
+
class tuple2(tuple):
pass
+
class tuple3(tuple):
def __repr__(self):
return tuple.__repr__(self)
+
class dict2(dict):
pass
+
class dict3(dict):
def __repr__(self):
return dict.__repr__(self)
@@ -101,7 +106,13 @@ class QueryTestCase(unittest.TestCase):
def test_same_as_repr(self):
# Simple objects, small containers and classes that overwrite __repr__
- # For those the result should be the same as repr()
+ # For those the result should be the same as repr().
+ # Ahem. The docs don't say anything about that -- this appears to
+ # be testing an implementation quirk. Starting in Python 2.5, it's
+ # not true for dicts: pprint always sorts dicts by key now; before,
+ # it sorted a dict display if and only if the display required
+ # multiple lines. For that reason, dicts with more than one element
+ # aren't tested here.
verify = self.assert_
for simple in (0, 0L, 0+0j, 0.0, "", uni(""),
(), tuple2(), tuple3(),
@@ -112,9 +123,7 @@ class QueryTestCase(unittest.TestCase):
(1,2), [3,4], {5: 6, 7: 8},
tuple2((1,2)), tuple3((1,2)), tuple3(range(100)),
[3,4], list2([3,4]), list3([3,4]), list3(range(100)),
- {5: 6, 7: 8}, dict2({5: 6, 7: 8}), dict3({5: 6, 7: 8}),
- dict3([(x,x) for x in range(100)]),
- {"xy\tab\n": (3,), 5: [[]], (): {}},
+ {5: 6, 7: 8}, dict2({5: 6}), dict3({5: 6}),
range(10, -11, -1)
):
native = repr(simple)
@@ -160,6 +169,24 @@ class QueryTestCase(unittest.TestCase):
for type in [list, list2]:
self.assertEqual(pprint.pformat(type(o), indent=4), exp)
+ def test_sorted_dict(self):
+ # Starting in Python 2.5, pprint sorts dict displays by key regardless
+ # of how small the dictionary may be.
+ # Before the change, on 32-bit Windows pformat() gave order
+ # 'a', 'c', 'b' here, so this test failed.
+ d = {'a': 1, 'b': 1, 'c': 1}
+ self.assertEqual(pprint.pformat(d), "{'a': 1, 'b': 1, 'c': 1}")
+ self.assertEqual(pprint.pformat([d, d]),
+ "[{'a': 1, 'b': 1, 'c': 1}, {'a': 1, 'b': 1, 'c': 1}]")
+
+ # The next one is kind of goofy. The sorted order depends on the
+ # alphabetic order of type names: "int" < "str" < "tuple". Before
+ # Python 2.5, this was in the test_same_as_repr() test. It's worth
+ # keeping around for now because it's one of few tests of pprint
+ # against a crazy mix of types.
+ self.assertEqual(pprint.pformat({"xy\tab\n": (3,), 5: [[]], (): {}}),
+ r"{5: [[]], 'xy\tab\n': (3,), (): {}}")
+
def test_subclassing(self):
o = {'names with spaces': 'should be presented using repr()',
'others.should.not.be': 'like.this'}
diff --git a/Lib/test/test_repr.py b/Lib/test/test_repr.py
index 9128585..1dfa282 100644
--- a/Lib/test/test_repr.py
+++ b/Lib/test/test_repr.py
@@ -5,6 +5,7 @@
import sys
import os
+import shutil
import unittest
from test.test_support import run_unittest
@@ -198,8 +199,10 @@ class LongReprTest(unittest.TestCase):
self.pkgname = os.path.join(longname)
self.subpkgname = os.path.join(longname, longname)
# Make the package and subpackage
+ shutil.rmtree(self.pkgname, ignore_errors=True)
os.mkdir(self.pkgname)
touch(os.path.join(self.pkgname, '__init__'+os.extsep+'py'))
+ shutil.rmtree(self.subpkgname, ignore_errors=True)
os.mkdir(self.subpkgname)
touch(os.path.join(self.subpkgname, '__init__'+os.extsep+'py'))
# Remember where we are
diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py
index 7981a52..af835f7 100644
--- a/Lib/test/test_struct.py
+++ b/Lib/test/test_struct.py
@@ -2,7 +2,7 @@ from test.test_support import TestFailed, verbose, verify
import test.test_support
import struct
import array
-import unittest
+import warnings
import sys
ISBIGENDIAN = sys.byteorder == "big"
@@ -10,7 +10,14 @@ del sys
verify((struct.pack('=i', 1)[0] == chr(0)) == ISBIGENDIAN,
"bigendian determination appears wrong")
-PY_STRUCT_RANGE_CHECKING = 1
+try:
+ import _struct
+except ImportError:
+ PY_STRUCT_RANGE_CHECKING = 0
+ PY_STRUCT_OVERFLOW_MASKING = 1
+else:
+ PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
+ PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
def string_reverse(s):
chars = list(s)
@@ -35,12 +42,39 @@ def simple_err(func, *args):
def any_err(func, *args):
try:
func(*args)
- except (struct.error, OverflowError, TypeError):
+ except (struct.error, TypeError):
pass
else:
raise TestFailed, "%s%s did not raise error" % (
func.__name__, args)
+def deprecated_err(func, *args):
+ # The `warnings` module doesn't have an advertised way to restore
+ # its filter list. Cheat.
+ save_warnings_filters = warnings.filters[:]
+ # Grrr, we need this function to warn every time. Without removing
+ # the warningregistry, running test_tarfile then test_struct would fail
+ # on 64-bit platforms.
+ globals = func.func_globals
+ if '__warningregistry__' in globals:
+ del globals['__warningregistry__']
+ warnings.filterwarnings("error", r"""^struct.*""", DeprecationWarning)
+ warnings.filterwarnings("error", r""".*format requires.*""",
+ DeprecationWarning)
+ try:
+ try:
+ func(*args)
+ except (struct.error, TypeError):
+ pass
+ except DeprecationWarning:
+ if not PY_STRUCT_OVERFLOW_MASKING:
+ raise TestFailed, "%s%s expected to raise struct.error" % (
+ func.__name__, args)
+ else:
+ raise TestFailed, "%s%s did not raise error" % (
+ func.__name__, args)
+ finally:
+ warnings.filters[:] = save_warnings_filters[:]
simple_err(struct.calcsize, 'Z')
@@ -272,8 +306,8 @@ class IntTester:
if verbose:
print "Skipping buggy range check for code", code
else:
- any_err(pack, ">" + code, x)
- any_err(pack, "<" + code, x)
+ deprecated_err(pack, ">" + code, x)
+ deprecated_err(pack, "<" + code, x)
# Much the same for unsigned.
code = self.unsigned_code
@@ -327,8 +361,8 @@ class IntTester:
if verbose:
print "Skipping buggy range check for code", code
else:
- any_err(pack, ">" + code, x)
- any_err(pack, "<" + code, x)
+ deprecated_err(pack, ">" + code, x)
+ deprecated_err(pack, "<" + code, x)
def run(self):
from random import randrange
@@ -448,91 +482,98 @@ def test_1229380():
for endian in ('', '>', '<'):
for cls in (int, long):
for fmt in ('B', 'H', 'I', 'L'):
- any_err(struct.pack, endian + fmt, cls(-1))
+ deprecated_err(struct.pack, endian + fmt, cls(-1))
- any_err(struct.pack, endian + 'B', cls(300))
- any_err(struct.pack, endian + 'H', cls(70000))
+ deprecated_err(struct.pack, endian + 'B', cls(300))
+ deprecated_err(struct.pack, endian + 'H', cls(70000))
- any_err(struct.pack, endian + 'I', sys.maxint * 4L)
- any_err(struct.pack, endian + 'L', sys.maxint * 4L)
+ deprecated_err(struct.pack, endian + 'I', sys.maxint * 4L)
+ deprecated_err(struct.pack, endian + 'L', sys.maxint * 4L)
if PY_STRUCT_RANGE_CHECKING:
test_1229380()
-class PackBufferTestCase(unittest.TestCase):
- """
- Test the packing methods that work on buffers.
- """
-
- def test_unpack_from( self ):
- test_string = 'abcd01234'
- fmt = '4s'
- s = struct.Struct(fmt)
- for cls in (str, buffer):
- data = cls(test_string)
- self.assertEquals(s.unpack_from(data), ('abcd',))
- self.assertEquals(s.unpack_from(data, 2), ('cd01',))
- self.assertEquals(s.unpack_from(data, 4), ('0123',))
- for i in xrange(6):
- self.assertEquals(s.unpack_from(data, i), (data[i:i+4],))
- for i in xrange(6, len(test_string) + 1):
- simple_err(s.unpack_from, data, i)
- for cls in (str, buffer):
- data = cls(test_string)
- self.assertEquals(struct.unpack_from(fmt, data), ('abcd',))
- self.assertEquals(struct.unpack_from(fmt, data, 2), ('cd01',))
- self.assertEquals(struct.unpack_from(fmt, data, 4), ('0123',))
- for i in xrange(6):
- self.assertEquals(struct.unpack_from(fmt, data, i),
- (data[i:i+4],))
- for i in xrange(6, len(test_string) + 1):
- simple_err(struct.unpack_from, fmt, data, i)
-
- def test_pack_to( self ):
- test_string = 'Reykjavik rocks, eow!'
- writable_buf = array.array('c', ' '*100)
- fmt = '21s'
- s = struct.Struct(fmt)
-
- # Test without offset
- s.pack_to(writable_buf, 0, test_string)
- from_buf = writable_buf.tostring()[:len(test_string)]
- self.assertEquals(from_buf, test_string)
-
- # Test with offset.
- s.pack_to(writable_buf, 10, test_string)
- from_buf = writable_buf.tostring()[:len(test_string)+10]
- self.assertEquals(from_buf, (test_string[:10] + test_string))
-
- # Go beyond boundaries.
- small_buf = array.array('c', ' '*10)
- self.assertRaises(struct.error, s.pack_to, small_buf, 0, test_string)
- self.assertRaises(struct.error, s.pack_to, small_buf, 2, test_string)
-
- def test_pack_to_fn( self ):
- test_string = 'Reykjavik rocks, eow!'
- writable_buf = array.array('c', ' '*100)
- fmt = '21s'
- pack_to = lambda *args: struct.pack_to(fmt, *args)
-
- # Test without offset
- pack_to(writable_buf, 0, test_string)
- from_buf = writable_buf.tostring()[:len(test_string)]
- self.assertEquals(from_buf, test_string)
-
- # Test with offset.
- pack_to(writable_buf, 10, test_string)
- from_buf = writable_buf.tostring()[:len(test_string)+10]
- self.assertEquals(from_buf, (test_string[:10] + test_string))
-
- # Go beyond boundaries.
- small_buf = array.array('c', ' '*10)
- self.assertRaises(struct.error, pack_to, small_buf, 0, test_string)
- self.assertRaises(struct.error, pack_to, small_buf, 2, test_string)
-
-
-def test_main():
- test.test_support.run_unittest(PackBufferTestCase)
-
-if __name__ == "__main__":
- test_main()
+
+###########################################################################
+# Packing and unpacking to/from buffers.
+
+# Copied and modified from unittest.
+def assertRaises(excClass, callableObj, *args, **kwargs):
+ try:
+ callableObj(*args, **kwargs)
+ except excClass:
+ return
+ else:
+ raise RuntimeError("%s not raised." % excClass)
+
+def test_unpack_from():
+ test_string = 'abcd01234'
+ fmt = '4s'
+ s = struct.Struct(fmt)
+ for cls in (str, buffer):
+ data = cls(test_string)
+ assert s.unpack_from(data) == ('abcd',)
+ assert s.unpack_from(data, 2) == ('cd01',)
+ assert s.unpack_from(data, 4) == ('0123',)
+ for i in xrange(6):
+ assert s.unpack_from(data, i) == (data[i:i+4],)
+ for i in xrange(6, len(test_string) + 1):
+ simple_err(s.unpack_from, data, i)
+ for cls in (str, buffer):
+ data = cls(test_string)
+ assert struct.unpack_from(fmt, data) == ('abcd',)
+ assert struct.unpack_from(fmt, data, 2) == ('cd01',)
+ assert struct.unpack_from(fmt, data, 4) == ('0123',)
+ for i in xrange(6):
+ assert (struct.unpack_from(fmt, data, i) == (data[i:i+4],))
+ for i in xrange(6, len(test_string) + 1):
+ simple_err(struct.unpack_from, fmt, data, i)
+
+def test_pack_to():
+ test_string = 'Reykjavik rocks, eow!'
+ writable_buf = array.array('c', ' '*100)
+ fmt = '21s'
+ s = struct.Struct(fmt)
+
+ # Test without offset
+ s.pack_to(writable_buf, 0, test_string)
+ from_buf = writable_buf.tostring()[:len(test_string)]
+ assert from_buf == test_string
+
+ # Test with offset.
+ s.pack_to(writable_buf, 10, test_string)
+ from_buf = writable_buf.tostring()[:len(test_string)+10]
+ assert from_buf == (test_string[:10] + test_string)
+
+ # Go beyond boundaries.
+ small_buf = array.array('c', ' '*10)
+ assertRaises(struct.error, s.pack_to, small_buf, 0, test_string)
+ assertRaises(struct.error, s.pack_to, small_buf, 2, test_string)
+
+def test_pack_to_fn():
+ test_string = 'Reykjavik rocks, eow!'
+ writable_buf = array.array('c', ' '*100)
+ fmt = '21s'
+ pack_to = lambda *args: struct.pack_to(fmt, *args)
+
+ # Test without offset
+ pack_to(writable_buf, 0, test_string)
+ from_buf = writable_buf.tostring()[:len(test_string)]
+ assert from_buf == test_string
+
+ # Test with offset.
+ pack_to(writable_buf, 10, test_string)
+ from_buf = writable_buf.tostring()[:len(test_string)+10]
+ assert from_buf == (test_string[:10] + test_string)
+
+ # Go beyond boundaries.
+ small_buf = array.array('c', ' '*10)
+ assertRaises(struct.error, pack_to, small_buf, 0, test_string)
+ assertRaises(struct.error, pack_to, small_buf, 2, test_string)
+
+
+# Test methods to pack and unpack from buffers rather than strings.
+test_unpack_from()
+test_pack_to()
+test_pack_to_fn()
+
diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py
index c8f19bc..034b9d0 100644
--- a/Lib/test/test_urllib2.py
+++ b/Lib/test/test_urllib2.py
@@ -76,10 +76,11 @@ def test_password_manager(self):
>>> mgr.find_user_password("c", "http://example.com/bar")
('bar', 'nini')
- Currently, we use the highest-level path where more than one match:
+ Actually, this is really undefined ATM
+## Currently, we use the highest-level path where more than one match:
- >>> mgr.find_user_password("Some Realm", "http://example.com/ni")
- ('joe', 'password')
+## >>> mgr.find_user_password("Some Realm", "http://example.com/ni")
+## ('joe', 'password')
Use latest add_password() in case of conflict:
@@ -110,6 +111,53 @@ def test_password_manager(self):
pass
+def test_password_manager_default_port(self):
+ """
+ >>> mgr = urllib2.HTTPPasswordMgr()
+ >>> add = mgr.add_password
+
+ The point to note here is that we can't guess the default port if there's
+ no scheme. This applies to both add_password and find_user_password.
+
+ >>> add("f", "http://g.example.com:80", "10", "j")
+ >>> add("g", "http://h.example.com", "11", "k")
+ >>> add("h", "i.example.com:80", "12", "l")
+ >>> add("i", "j.example.com", "13", "m")
+ >>> mgr.find_user_password("f", "g.example.com:100")
+ (None, None)
+ >>> mgr.find_user_password("f", "g.example.com:80")
+ ('10', 'j')
+ >>> mgr.find_user_password("f", "g.example.com")
+ (None, None)
+ >>> mgr.find_user_password("f", "http://g.example.com:100")
+ (None, None)
+ >>> mgr.find_user_password("f", "http://g.example.com:80")
+ ('10', 'j')
+ >>> mgr.find_user_password("f", "http://g.example.com")
+ ('10', 'j')
+ >>> mgr.find_user_password("g", "h.example.com")
+ ('11', 'k')
+ >>> mgr.find_user_password("g", "h.example.com:80")
+ ('11', 'k')
+ >>> mgr.find_user_password("g", "http://h.example.com:80")
+ ('11', 'k')
+ >>> mgr.find_user_password("h", "i.example.com")
+ (None, None)
+ >>> mgr.find_user_password("h", "i.example.com:80")
+ ('12', 'l')
+ >>> mgr.find_user_password("h", "http://i.example.com:80")
+ ('12', 'l')
+ >>> mgr.find_user_password("i", "j.example.com")
+ ('13', 'm')
+ >>> mgr.find_user_password("i", "j.example.com:80")
+ (None, None)
+ >>> mgr.find_user_password("i", "http://j.example.com")
+ ('13', 'm')
+ >>> mgr.find_user_password("i", "http://j.example.com:80")
+ (None, None)
+
+ """
+
class MockOpener:
addheaders = []
def open(self, req, data=None):
@@ -270,6 +318,27 @@ class MockPasswordManager:
class OpenerDirectorTests(unittest.TestCase):
+ def test_badly_named_methods(self):
+ # test work-around for three methods that accidentally follow the
+ # naming conventions for handler methods
+ # (*_open() / *_request() / *_response())
+
+ # These used to call the accidentally-named methods, causing a
+ # TypeError in real code; here, returning self from these mock
+ # methods would either cause no exception, or AttributeError.
+
+ from urllib2 import URLError
+
+ o = OpenerDirector()
+ meth_spec = [
+ [("do_open", "return self"), ("proxy_open", "return self")],
+ [("redirect_request", "return self")],
+ ]
+ handlers = add_ordered_mock_handlers(o, meth_spec)
+ o.add_handler(urllib2.UnknownHandler())
+ for scheme in "do", "proxy", "redirect":
+ self.assertRaises(URLError, o.open, scheme+"://example.com/")
+
def test_handled(self):
# handler returning non-None means no more handlers will be called
o = OpenerDirector()
@@ -560,6 +629,7 @@ class HandlerTests(unittest.TestCase):
self.method = method
self.selector = url
self.req_headers += headers.items()
+ self.req_headers.sort()
if body:
self.data = body
if self.raise_on_endheaders:
@@ -758,6 +828,8 @@ class HandlerTests(unittest.TestCase):
realm = "ACME Widget Store"
http_handler = MockHTTPHandler(
401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
+ opener.add_handler(auth_handler)
+ opener.add_handler(http_handler)
self._test_basic_auth(opener, auth_handler, "Authorization",
realm, http_handler, password_manager,
"http://acme.example.com/protected",
@@ -773,6 +845,8 @@ class HandlerTests(unittest.TestCase):
realm = "ACME Networks"
http_handler = MockHTTPHandler(
407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
+ opener.add_handler(auth_handler)
+ opener.add_handler(http_handler)
self._test_basic_auth(opener, auth_handler, "Proxy-authorization",
realm, http_handler, password_manager,
"http://acme.example.com:3128/protected",
@@ -784,29 +858,53 @@ class HandlerTests(unittest.TestCase):
# response (http://python.org/sf/1479302), where it should instead
# return None to allow another handler (especially
# HTTPBasicAuthHandler) to handle the response.
+
+ # Also (http://python.org/sf/14797027, RFC 2617 section 1.2), we must
+ # try digest first (since it's the strongest auth scheme), so we record
+ # order of calls here to check digest comes first:
+ class RecordingOpenerDirector(OpenerDirector):
+ def __init__(self):
+ OpenerDirector.__init__(self)
+ self.recorded = []
+ def record(self, info):
+ self.recorded.append(info)
class TestDigestAuthHandler(urllib2.HTTPDigestAuthHandler):
- handler_order = 400 # strictly before HTTPBasicAuthHandler
- opener = OpenerDirector()
+ def http_error_401(self, *args, **kwds):
+ self.parent.record("digest")
+ urllib2.HTTPDigestAuthHandler.http_error_401(self,
+ *args, **kwds)
+ class TestBasicAuthHandler(urllib2.HTTPBasicAuthHandler):
+ def http_error_401(self, *args, **kwds):
+ self.parent.record("basic")
+ urllib2.HTTPBasicAuthHandler.http_error_401(self,
+ *args, **kwds)
+
+ opener = RecordingOpenerDirector()
password_manager = MockPasswordManager()
digest_handler = TestDigestAuthHandler(password_manager)
- basic_handler = urllib2.HTTPBasicAuthHandler(password_manager)
- opener.add_handler(digest_handler)
+ basic_handler = TestBasicAuthHandler(password_manager)
realm = "ACME Networks"
http_handler = MockHTTPHandler(
401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
+ opener.add_handler(basic_handler)
+ opener.add_handler(digest_handler)
+ opener.add_handler(http_handler)
+
+ # check basic auth isn't blocked by digest handler failing
self._test_basic_auth(opener, basic_handler, "Authorization",
realm, http_handler, password_manager,
"http://acme.example.com/protected",
"http://acme.example.com/protected",
)
+ # check digest was tried before basic (twice, because
+ # _test_basic_auth called .open() twice)
+ self.assertEqual(opener.recorded, ["digest", "basic"]*2)
def _test_basic_auth(self, opener, auth_handler, auth_header,
realm, http_handler, password_manager,
request_url, protected_url):
import base64, httplib
user, password = "wile", "coyote"
- opener.add_handler(auth_handler)
- opener.add_handler(http_handler)
# .add_password() fed through to password manager
auth_handler.add_password(realm, request_url, user, password)
diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py
index 392e5fa..18ab401 100644
--- a/Lib/test/test_weakref.py
+++ b/Lib/test/test_weakref.py
@@ -1053,8 +1053,8 @@ libreftest = """ Doctest for examples in the library reference: libweakref.tex
...
>>> obj = Dict(red=1, green=2, blue=3) # this object is weak referencable
>>> r = weakref.ref(obj)
->>> print r()
-{'blue': 3, 'green': 2, 'red': 1}
+>>> print r() is obj
+True
>>> import weakref
>>> class Object:
diff --git a/Lib/urllib2.py b/Lib/urllib2.py
index cdb3a22..227311c 100644
--- a/Lib/urllib2.py
+++ b/Lib/urllib2.py
@@ -297,6 +297,10 @@ class OpenerDirector:
def add_handler(self, handler):
added = False
for meth in dir(handler):
+ if meth in ["redirect_request", "do_open", "proxy_open"]:
+ # oops, coincidental match
+ continue
+
i = meth.find("_")
protocol = meth[:i]
condition = meth[i+1:]
@@ -695,32 +699,45 @@ class HTTPPasswordMgr:
# uri could be a single URI or a sequence
if isinstance(uri, basestring):
uri = [uri]
- uri = tuple(map(self.reduce_uri, uri))
if not realm in self.passwd:
self.passwd[realm] = {}
- self.passwd[realm][uri] = (user, passwd)
+ for default_port in True, False:
+ reduced_uri = tuple(
+ [self.reduce_uri(u, default_port) for u in uri])
+ self.passwd[realm][reduced_uri] = (user, passwd)
def find_user_password(self, realm, authuri):
domains = self.passwd.get(realm, {})
- authuri = self.reduce_uri(authuri)
- for uris, authinfo in domains.iteritems():
- for uri in uris:
- if self.is_suburi(uri, authuri):
- return authinfo
+ for default_port in True, False:
+ reduced_authuri = self.reduce_uri(authuri, default_port)
+ for uris, authinfo in domains.iteritems():
+ for uri in uris:
+ if self.is_suburi(uri, reduced_authuri):
+ return authinfo
return None, None
- def reduce_uri(self, uri):
- """Accept netloc or URI and extract only the netloc and path"""
+ def reduce_uri(self, uri, default_port=True):
+ """Accept authority or URI and extract only the authority and path."""
+ # note HTTP URLs do not have a userinfo component
parts = urlparse.urlsplit(uri)
if parts[1]:
# URI
- return parts[1], parts[2] or '/'
- elif parts[0]:
- # host:port
- return uri, '/'
+ scheme = parts[0]
+ authority = parts[1]
+ path = parts[2] or '/'
else:
- # host
- return parts[2], '/'
+ # host or host:port
+ scheme = None
+ authority = uri
+ path = '/'
+ host, port = splitport(authority)
+ if default_port and port is None and scheme is not None:
+ dport = {"http": 80,
+ "https": 443,
+ }.get(scheme)
+ if dport is not None:
+ authority = "%s:%d" % (host, dport)
+ return authority, path
def is_suburi(self, base, test):
"""Check if test is below base in a URI tree
@@ -755,6 +772,10 @@ class AbstractBasicAuthHandler:
# www-authenticate header. should probably be a lot more careful
# in parsing them to extract multiple alternatives
+ # XXX could pre-emptively send auth info already accepted (RFC 2617,
+ # end of section 2, and section 1.2 immediately after "credentials"
+ # production).
+
def __init__(self, password_mgr=None):
if password_mgr is None:
password_mgr = HTTPPasswordMgr()
@@ -964,6 +985,7 @@ class HTTPDigestAuthHandler(BaseHandler, AbstractDigestAuthHandler):
"""
auth_header = 'Authorization'
+ handler_order = 490 # before Basic auth
def http_error_401(self, req, fp, code, msg, headers):
host = urlparse.urlparse(req.get_full_url())[1]
@@ -976,6 +998,7 @@ class HTTPDigestAuthHandler(BaseHandler, AbstractDigestAuthHandler):
class ProxyDigestAuthHandler(BaseHandler, AbstractDigestAuthHandler):
auth_header = 'Proxy-Authorization'
+ handler_order = 490 # before Basic auth
def http_error_407(self, req, fp, code, msg, headers):
host = req.get_host()