Merge with hg.python.org.

This commit is contained in:
Reid Kleckner 2011-03-14 19:34:13 -04:00
commit a9b3a1c49d
16 changed files with 231 additions and 75 deletions

View File

@ -387,6 +387,11 @@ All of the functions and methods that accept a *timeout* parameter, such as
:func:`call` and :meth:`Popen.communicate` will raise :exc:`TimeoutExpired` if
the timeout expires before the process exits.
Exceptions defined in this module all inherit from :ext:`SubprocessError`.
.. versionadded:: 3.3
The :exc:`SubprocessError` base class was added.
Security
^^^^^^^^

View File

@ -723,7 +723,7 @@ Test cases
Here, we create two instances of :class:`WidgetTestCase`, each of which runs a
single test.
.. versionchanged::
.. versionchanged:: 3.2
`TestCase` can be instantiated successfully without providing a method
name. This makes it easier to experiment with `TestCase` from the
interactive interpreter.
@ -792,11 +792,14 @@ Test cases
Run the test, collecting the result into the test result object passed as
*result*. If *result* is omitted or ``None``, a temporary result
object is created (by calling the :meth:`defaultTestResult` method) and
used. The result object is not returned to :meth:`run`'s caller.
used. The result object is returned to :meth:`run`'s caller.
The same effect may be had by simply calling the :class:`TestCase`
instance.
.. versionchanged:: 3.3
Previous versions of ``run`` did not return the result. Neither did
calling an instance.
.. method:: skipTest(reason)

View File

@ -67,10 +67,10 @@ def open(file, flag = 'r', mode = 0o666):
if not _defaultmod:
raise ImportError("no dbm clone found; tried %s" % _names)
# guess the type of an existing database
result = whichdb(file)
# guess the type of an existing database, if not creating a new one
result = whichdb(file) if 'n' not in flag else None
if result is None:
# db doesn't exist
# db doesn't exist or 'n' flag was specified to create a new db
if 'c' in flag or 'n' in flag:
# file doesn't exist and the new flag was used so use default type
mod = _defaultmod

View File

@ -59,7 +59,7 @@ class Generator:
self._fp.write(s)
def flatten(self, msg, unixfrom=False, linesep='\n'):
"""Print the message object tree rooted at msg to the output file
r"""Print the message object tree rooted at msg to the output file
specified when the Generator instance was created.
unixfrom is a flag that forces the printing of a Unix From_ delimiter
@ -70,7 +70,10 @@ class Generator:
Note that for subobjects, no From_ line is printed.
linesep specifies the characters used to indicate a new line in
the output.
the output. The default value is the most useful for typical
Python applications, but it can be set to \r\n to produce RFC-compliant
line separators when needed.
"""
# We use the _XXX constants for operating on data that comes directly
# from the msg, and _encoded_XXX constants for operating on data that

View File

@ -276,7 +276,7 @@ class Header:
self._chunks.append((s, charset))
def encode(self, splitchars=';, \t', maxlinelen=None, linesep='\n'):
"""Encode a message header into an RFC-compliant format.
r"""Encode a message header into an RFC-compliant format.
There are many issues involved in converting a given string for use in
an email header. Only certain character sets are readable in most

View File

@ -191,8 +191,10 @@ should prepare for OSErrors.
A ValueError will be raised if Popen is called with invalid arguments.
check_call() and check_output() will raise CalledProcessError, if the
called process returns a non-zero return code.
Exceptions defined within this module inherit from SubprocessError.
check_call() and check_output() will raise CalledProcessError if the
called process returns a non-zero return code. TimeoutExpired
be raised if a timeout was specified and expired.
Security
@ -348,7 +350,10 @@ import builtins
import warnings
# Exception classes used by this module.
class CalledProcessError(Exception):
class SubprocessError(Exception): pass
class CalledProcessError(SubprocessError):
"""This exception is raised when a process run by check_call() or
check_output() returns a non-zero exit status.
The exit status will be stored in the returncode attribute;
@ -362,7 +367,7 @@ class CalledProcessError(Exception):
return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
class TimeoutExpired(Exception):
class TimeoutExpired(SubprocessError):
"""This exception is raised when the timeout expires while waiting for a
child process.
"""

View File

@ -70,6 +70,14 @@ class AnyDBMTestCase(unittest.TestCase):
self.read_helper(f)
f.close()
def test_anydbm_creation_n_file_exists_with_invalid_contents(self):
with open(_fname, "w") as w:
pass # create an empty file
f = dbm.open(_fname, 'n')
self.addCleanup(f.close)
self.assertEqual(len(f), 0)
def test_anydbm_modification(self):
self.init_db()
f = dbm.open(_fname, 'c')

View File

@ -42,6 +42,19 @@ class TestTemplate(unittest.TestCase):
s = Template('$who likes $$')
eq(s.substitute(dict(who='tim', what='ham')), 'tim likes $')
def test_invalid(self):
class MyPattern(Template):
pattern = r"""
(?:
(?P<invalid>) |
(?P<escaped>%(delim)s) |
@(?P<named>%(id)s) |
@{(?P<braced>%(id)s)}
)
"""
s = MyPattern('$')
self.assertRaises(ValueError, s.substitute, dict())
def test_percents(self):
eq = self.assertEqual
s = Template('%(foo)s $foo ${foo}')

View File

@ -12,6 +12,10 @@ from test.support import run_unittest, import_module
readline = import_module('readline')
class TestHistoryManipulation (unittest.TestCase):
@unittest.skipIf(not hasattr(readline, 'clear_history'),
"The history update test cannot be run because the "
"clear_history method is not available.")
def testHistoryUpdates(self):
readline.clear_history()

View File

@ -112,6 +112,30 @@ class ModuleTest(unittest.TestCase):
self.assertRaises(ValueError, fmt.format, "{0}", 10, 20, i=100)
self.assertRaises(ValueError, fmt.format, "{i}", 10, 20, i=100)
def test_vformat_assert(self):
cls = string.Formatter()
kwargs = {
"i": 100
}
self.assertRaises(ValueError, cls._vformat,
cls.format, "{0}", kwargs, set(), -2)
def test_convert_field(self):
cls = string.Formatter()
self.assertEqual(cls.format("{0!s}", 'foo'), 'foo')
self.assertRaises(ValueError, cls.format, "{0!h}", 'foo')
def test_get_field(self):
cls = string.Formatter()
class MyClass:
name = 'lumberjack'
x = MyClass()
self.assertEqual(cls.format("{0.name}", x), 'lumberjack')
lookup = ["eggs", "and", "spam"]
self.assertEqual(cls.format("{0[2]}", lookup), 'spam')
def test_main():
support.run_unittest(ModuleTest)

View File

@ -7,7 +7,9 @@ import socket
import array
import urllib.request
from urllib.request import Request, OpenerDirector
# The proxy bypass method imported below has logic specific to the OSX
# proxy config data structure but is testable on all platforms.
from urllib.request import Request, OpenerDirector, _proxy_bypass_macosx_sysconf
# XXX
# Request
@ -1076,6 +1078,17 @@ class HandlerTests(unittest.TestCase):
self.assertEqual(req.get_host(), "www.python.org")
del os.environ['no_proxy']
def test_proxy_no_proxy_all(self):
os.environ['no_proxy'] = '*'
o = OpenerDirector()
ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
o.add_handler(ph)
req = Request("http://www.python.org")
self.assertEqual(req.get_host(), "www.python.org")
r = o.open(req)
self.assertEqual(req.get_host(), "www.python.org")
del os.environ['no_proxy']
def test_proxy_https(self):
o = OpenerDirector()
@ -1116,6 +1129,26 @@ class HandlerTests(unittest.TestCase):
self.assertEqual(req.get_host(), "proxy.example.com:3128")
self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
def test_osx_proxy_bypass(self):
bypass = {
'exclude_simple': False,
'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.10',
'10.0/16']
}
# Check hosts that should trigger the proxy bypass
for host in ('foo.bar', 'www.bar.com', '127.0.0.1', '10.10.0.1',
'10.0.0.1'):
self.assertTrue(_proxy_bypass_macosx_sysconf(host, bypass),
'expected bypass of %s to be True' % host)
# Check hosts that should not trigger the proxy bypass
for host in ('abc.foo.bar', 'bar.com', '127.0.0.2', '10.11.0.1', 'test'):
self.assertFalse(_proxy_bypass_macosx_sysconf(host, bypass),
'expected bypass of %s to be False' % host)
# Check the exclude_simple flag
bypass = {'exclude_simple': True, 'exceptions': []}
self.assertTrue(_proxy_bypass_macosx_sysconf('test', bypass))
def test_basic_auth(self, quote_char='"'):
opener = OpenerDirector()
password_manager = MockPasswordManager()

View File

@ -469,7 +469,7 @@ class TestCase(object):
warnings.warn("TestResult has no addExpectedFailure method, reporting as passes",
RuntimeWarning)
result.addSuccess(self)
return result
finally:
result.stopTest(self)
if orig_result is None:

View File

@ -386,27 +386,62 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
self.assertIsInstance(Foo().id(), str)
# "If result is omitted or None, a temporary result object is created
# and used, but is not made available to the caller. As TestCase owns the
# "If result is omitted or None, a temporary result object is created,
# used, and is made available to the caller. As TestCase owns the
# temporary result startTestRun and stopTestRun are called.
def test_run__uses_defaultTestResult(self):
events = []
defaultResult = LoggingResult(events)
class Foo(unittest.TestCase):
def test(self):
events.append('test')
def defaultTestResult(self):
return LoggingResult(events)
return defaultResult
# Make run() find a result object on its own
Foo('test').run()
result = Foo('test').run()
self.assertIs(result, defaultResult)
expected = ['startTestRun', 'startTest', 'test', 'addSuccess',
'stopTest', 'stopTestRun']
self.assertEqual(events, expected)
# "The result object is returned to run's caller"
def test_run__returns_given_result(self):
class Foo(unittest.TestCase):
def test(self):
pass
result = unittest.TestResult()
retval = Foo('test').run(result)
self.assertIs(retval, result)
# "The same effect [as method run] may be had by simply calling the
# TestCase instance."
def test_call__invoking_an_instance_delegates_to_run(self):
resultIn = unittest.TestResult()
resultOut = unittest.TestResult()
class Foo(unittest.TestCase):
def test(self):
pass
def run(self, result):
self.assertIs(result, resultIn)
return resultOut
retval = Foo('test')(resultIn)
self.assertIs(retval, resultOut)
def testShortDescriptionWithoutDocstring(self):
self.assertIsNone(self.shortDescription())

View File

@ -2208,68 +2208,76 @@ def proxy_bypass_environment(host):
return 0
# This code tests an OSX specific data structure but is testable on all
# platforms
def _proxy_bypass_macosx_sysconf(host, proxy_settings):
"""
Return True iff this host shouldn't be accessed using a proxy
This function uses the MacOSX framework SystemConfiguration
to fetch the proxy information.
proxy_settings come from _scproxy._get_proxy_settings or get mocked ie:
{ 'exclude_simple': bool,
'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.1', '10.0/16']
}
"""
import re
import socket
from fnmatch import fnmatch
hostonly, port = splitport(host)
def ip2num(ipAddr):
parts = ipAddr.split('.')
parts = list(map(int, parts))
if len(parts) != 4:
parts = (parts + [0, 0, 0, 0])[:4]
return (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]
# Check for simple host names:
if '.' not in host:
if proxy_settings['exclude_simple']:
return True
hostIP = None
for value in proxy_settings.get('exceptions', ()):
# Items in the list are strings like these: *.local, 169.254/16
if not value: continue
m = re.match(r"(\d+(?:\.\d+)*)(/\d+)?", value)
if m is not None:
if hostIP is None:
try:
hostIP = socket.gethostbyname(hostonly)
hostIP = ip2num(hostIP)
except socket.error:
continue
base = ip2num(m.group(1))
mask = m.group(2)
if mask is None:
mask = 8 * (m.group(1).count('.') + 1)
else:
mask = int(mask[1:])
mask = 32 - mask
if (hostIP >> mask) == (base >> mask):
return True
elif fnmatch(host, value):
return True
return False
if sys.platform == 'darwin':
from _scproxy import _get_proxy_settings, _get_proxies
def proxy_bypass_macosx_sysconf(host):
"""
Return True iff this host shouldn't be accessed using a proxy
This function uses the MacOSX framework SystemConfiguration
to fetch the proxy information.
"""
import re
import socket
from fnmatch import fnmatch
hostonly, port = splitport(host)
def ip2num(ipAddr):
parts = ipAddr.split('.')
parts = list(map(int, parts))
if len(parts) != 4:
parts = (parts + [0, 0, 0, 0])[:4]
return (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]
proxy_settings = _get_proxy_settings()
# Check for simple host names:
if '.' not in host:
if proxy_settings['exclude_simple']:
return True
hostIP = None
for value in proxy_settings.get('exceptions', ()):
# Items in the list are strings like these: *.local, 169.254/16
if not value: continue
m = re.match(r"(\d+(?:\.\d+)*)(/\d+)?", value)
if m is not None:
if hostIP is None:
try:
hostIP = socket.gethostbyname(hostonly)
hostIP = ip2num(hostIP)
except socket.error:
continue
base = ip2num(m.group(1))
mask = m.group(2)
if mask is None:
mask = 8 * (m.group(1).count('.') + 1)
else:
mask = int(mask[1:])
mask = 32 - mask
if (hostIP >> mask) == (base >> mask):
return True
elif fnmatch(host, value):
return True
return False
return _proxy_bypass_macosx_sysconf(host, proxy_settings)
def getproxies_macosx_sysconf():
"""Return a dictionary of scheme -> proxy server URL mappings.

View File

@ -32,6 +32,7 @@ Oliver Andrich
Ross Andrus
Jon Anglin
Éric Araujo
Alicia Arlen
Jason Asbahr
David Ascher
Chris AtLee
@ -171,6 +172,7 @@ Benjamin Collar
Jeffery Collins
Robert Collins
Paul Colomiets
Denver Coneybeare
Geremy Condra
Juan José Conti
Matt Conway
@ -350,6 +352,7 @@ Lynda Hardman
Derek Harland
Jason Harper
Brian Harring
Jonathan Hartley
Larry Hastings
Shane Hathaway
Rycharde Hawkes

View File

@ -68,6 +68,16 @@ Core and Builtins
Library
-------
- Issue #11407: `TestCase.run` returns the result object used or created.
Contributed by Janathan Hartley.
- Issue #11500: Fixed a bug in the os x proxy bypass code for fully qualified
IP addresses in the proxy exception list.
- Issue #11491: dbm.error is no longer raised when dbm.open is called with
the "n" as the flag argument and the file exists. The behavior matches
the documentation and general logic.
- Issue #1162477: Postel Principal adjustment to email date parsing: handle the
fact that some non-compliant MUAs use '.' instead of ':' in time specs.
@ -193,6 +203,8 @@ Tools/Demos
Tests
-----
- Issue #11505: improves test coverage of string.py
- Issue #11490: test_subprocess:test_leaking_fds_on_error no longer gives a
false positive if the last directory in the path is inaccessible.