Merge with hg.python.org.
This commit is contained in:
commit
a9b3a1c49d
|
@ -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
|
||||
^^^^^^^^
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
"""
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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}')
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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())
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
12
Misc/NEWS
12
Misc/NEWS
|
@ -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.
|
||||
|
||||
|
|
Loading…
Reference in New Issue