Merge from 3.5.0 branch.

This commit is contained in:
Steve Dower 2015-09-06 22:27:42 -07:00
commit f35bd306ff
14 changed files with 210 additions and 144 deletions

View file

@ -334,6 +334,12 @@ if create_dynamic:
""" """
import importlib.machinery import importlib.machinery
loader = importlib.machinery.ExtensionFileLoader(name, path) loader = importlib.machinery.ExtensionFileLoader(name, path)
return loader.load_module()
# Issue #24748: Skip the sys.modules check in _load_module_shim;
# always load new extension
spec = importlib.machinery.ModuleSpec(
name=name, loader=loader, origin=path)
return _load(spec)
else: else:
load_dynamic = None load_dynamic = None

3
Lib/test/imp_dummy.py Normal file
View file

@ -0,0 +1,3 @@
# Fodder for test of issue24748 in test_imp
dummy_name = True

View file

@ -3,6 +3,7 @@ try:
except ImportError: except ImportError:
_thread = None _thread = None
import importlib import importlib
import importlib.util
import os import os
import os.path import os.path
import shutil import shutil
@ -275,6 +276,29 @@ class ImportTests(unittest.TestCase):
self.skipTest("found module doesn't appear to be a C extension") self.skipTest("found module doesn't appear to be a C extension")
imp.load_module(name, None, *found[1:]) imp.load_module(name, None, *found[1:])
@requires_load_dynamic
def test_issue24748_load_module_skips_sys_modules_check(self):
name = 'test.imp_dummy'
try:
del sys.modules[name]
except KeyError:
pass
try:
module = importlib.import_module(name)
spec = importlib.util.find_spec('_testmultiphase')
module = imp.load_dynamic(name, spec.origin)
self.assertEqual(module.__name__, name)
self.assertEqual(module.__spec__.name, name)
self.assertEqual(module.__spec__.origin, spec.origin)
self.assertRaises(AttributeError, getattr, module, 'dummy_name')
self.assertEqual(module.int_const, 1969)
self.assertIs(sys.modules[name], module)
finally:
try:
del sys.modules[name]
except KeyError:
pass
@unittest.skipIf(sys.dont_write_bytecode, @unittest.skipIf(sys.dont_write_bytecode,
"test meaningful only when writing bytecode") "test meaningful only when writing bytecode")
def test_bug7732(self): def test_bug7732(self):

View file

@ -174,6 +174,19 @@ class TimeTestCase(unittest.TestCase):
def test_strftime_bounding_check(self): def test_strftime_bounding_check(self):
self._bounds_checking(lambda tup: time.strftime('', tup)) self._bounds_checking(lambda tup: time.strftime('', tup))
def test_strftime_format_check(self):
# Test that strftime does not crash on invalid format strings
# that may trigger a buffer overread. When not triggered,
# strftime may succeed or raise ValueError depending on
# the platform.
for x in [ '', 'A', '%A', '%AA' ]:
for y in range(0x0, 0x10):
for z in [ '%', 'A%', 'AA%', '%A%', 'A%A%', '%#' ]:
try:
time.strftime(x * y + z)
except ValueError:
pass
def test_default_values_for_zero(self): def test_default_values_for_zero(self):
# Make sure that using all zeros uses the proper default # Make sure that using all zeros uses the proper default
# values. No test for daylight savings since strftime() does # values. No test for daylight savings since strftime() does

View file

@ -7,7 +7,7 @@ import unittest
from test import support from test import support
from test.support.script_helper import assert_python_ok, assert_python_failure from test.support.script_helper import assert_python_ok, assert_python_failure
from test import warning_tests from test.test_warnings.data import stacklevel as warning_tests
import warnings as original_warnings import warnings as original_warnings
@ -44,7 +44,6 @@ class BaseTest:
"""Basic bookkeeping required for testing.""" """Basic bookkeeping required for testing."""
def setUp(self): def setUp(self):
self.old_unittest_module = unittest.case.warnings
# The __warningregistry__ needs to be in a pristine state for tests # The __warningregistry__ needs to be in a pristine state for tests
# to work properly. # to work properly.
if '__warningregistry__' in globals(): if '__warningregistry__' in globals():
@ -56,15 +55,10 @@ class BaseTest:
# The 'warnings' module must be explicitly set so that the proper # The 'warnings' module must be explicitly set so that the proper
# interaction between _warnings and 'warnings' can be controlled. # interaction between _warnings and 'warnings' can be controlled.
sys.modules['warnings'] = self.module sys.modules['warnings'] = self.module
# Ensure that unittest.TestCase.assertWarns() uses the same warnings
# module than warnings.catch_warnings(). Otherwise,
# warnings.catch_warnings() will be unable to remove the added filter.
unittest.case.warnings = self.module
super(BaseTest, self).setUp() super(BaseTest, self).setUp()
def tearDown(self): def tearDown(self):
sys.modules['warnings'] = original_warnings sys.modules['warnings'] = original_warnings
unittest.case.warnings = self.old_unittest_module
super(BaseTest, self).tearDown() super(BaseTest, self).tearDown()
class PublicAPITests(BaseTest): class PublicAPITests(BaseTest):
@ -194,11 +188,11 @@ class FilterTests(BaseTest):
self.module.resetwarnings() self.module.resetwarnings()
self.module.filterwarnings("once", category=UserWarning) self.module.filterwarnings("once", category=UserWarning)
message = UserWarning("FilterTests.test_once") message = UserWarning("FilterTests.test_once")
self.module.warn_explicit(message, UserWarning, "test_warnings.py", self.module.warn_explicit(message, UserWarning, "__init__.py",
42) 42)
self.assertEqual(w[-1].message, message) self.assertEqual(w[-1].message, message)
del w[:] del w[:]
self.module.warn_explicit(message, UserWarning, "test_warnings.py", self.module.warn_explicit(message, UserWarning, "__init__.py",
13) 13)
self.assertEqual(len(w), 0) self.assertEqual(len(w), 0)
self.module.warn_explicit(message, UserWarning, "test_warnings2.py", self.module.warn_explicit(message, UserWarning, "test_warnings2.py",
@ -304,10 +298,10 @@ class WarnTests(BaseTest):
module=self.module) as w: module=self.module) as w:
warning_tests.inner("spam1") warning_tests.inner("spam1")
self.assertEqual(os.path.basename(w[-1].filename), self.assertEqual(os.path.basename(w[-1].filename),
"warning_tests.py") "stacklevel.py")
warning_tests.outer("spam2") warning_tests.outer("spam2")
self.assertEqual(os.path.basename(w[-1].filename), self.assertEqual(os.path.basename(w[-1].filename),
"warning_tests.py") "stacklevel.py")
def test_stacklevel(self): def test_stacklevel(self):
# Test stacklevel argument # Test stacklevel argument
@ -317,25 +311,36 @@ class WarnTests(BaseTest):
module=self.module) as w: module=self.module) as w:
warning_tests.inner("spam3", stacklevel=1) warning_tests.inner("spam3", stacklevel=1)
self.assertEqual(os.path.basename(w[-1].filename), self.assertEqual(os.path.basename(w[-1].filename),
"warning_tests.py") "stacklevel.py")
warning_tests.outer("spam4", stacklevel=1) warning_tests.outer("spam4", stacklevel=1)
self.assertEqual(os.path.basename(w[-1].filename), self.assertEqual(os.path.basename(w[-1].filename),
"warning_tests.py") "stacklevel.py")
warning_tests.inner("spam5", stacklevel=2) warning_tests.inner("spam5", stacklevel=2)
self.assertEqual(os.path.basename(w[-1].filename), self.assertEqual(os.path.basename(w[-1].filename),
"test_warnings.py") "__init__.py")
warning_tests.outer("spam6", stacklevel=2) warning_tests.outer("spam6", stacklevel=2)
self.assertEqual(os.path.basename(w[-1].filename), self.assertEqual(os.path.basename(w[-1].filename),
"warning_tests.py") "stacklevel.py")
warning_tests.outer("spam6.5", stacklevel=3) warning_tests.outer("spam6.5", stacklevel=3)
self.assertEqual(os.path.basename(w[-1].filename), self.assertEqual(os.path.basename(w[-1].filename),
"test_warnings.py") "__init__.py")
warning_tests.inner("spam7", stacklevel=9999) warning_tests.inner("spam7", stacklevel=9999)
self.assertEqual(os.path.basename(w[-1].filename), self.assertEqual(os.path.basename(w[-1].filename),
"sys") "sys")
def test_stacklevel_import(self):
# Issue #24305: With stacklevel=2, module-level warnings should work.
support.unload('test.test_warnings.data.import_warning')
with warnings_state(self.module):
with original_warnings.catch_warnings(record=True,
module=self.module) as w:
self.module.simplefilter('always')
import test.test_warnings.data.import_warning
self.assertEqual(len(w), 1)
self.assertEqual(w[0].filename, __file__)
def test_missing_filename_not_main(self): def test_missing_filename_not_main(self):
# If __file__ is not specified and __main__ is not the module name, # If __file__ is not specified and __main__ is not the module name,
# then __file__ should be set to the module name. # then __file__ should be set to the module name.

View file

@ -0,0 +1,3 @@
import unittest
unittest.main('test.test_warnings')

View file

@ -0,0 +1,3 @@
import warnings
warnings.warn('module-level warning', DeprecationWarning, stacklevel=2)

View file

@ -160,6 +160,20 @@ def _getcategory(category):
return cat return cat
def _is_internal_frame(frame):
"""Signal whether the frame is an internal CPython implementation detail."""
filename = frame.f_code.co_filename
return 'importlib' in filename and '_bootstrap' in filename
def _next_external_frame(frame):
"""Find the next frame that doesn't involve CPython internals."""
frame = frame.f_back
while frame is not None and _is_internal_frame(frame):
frame = frame.f_back
return frame
# Code typically replaced by _warnings # Code typically replaced by _warnings
def warn(message, category=None, stacklevel=1): def warn(message, category=None, stacklevel=1):
"""Issue a warning, or maybe ignore it or raise an exception.""" """Issue a warning, or maybe ignore it or raise an exception."""
@ -174,13 +188,23 @@ def warn(message, category=None, stacklevel=1):
"not '{:s}'".format(type(category).__name__)) "not '{:s}'".format(type(category).__name__))
# Get context information # Get context information
try: try:
caller = sys._getframe(stacklevel) if stacklevel <= 1 or _is_internal_frame(sys._getframe(1)):
# If frame is too small to care or if the warning originated in
# internal code, then do not try to hide any frames.
frame = sys._getframe(stacklevel)
else:
frame = sys._getframe(1)
# Look for one frame less since the above line starts us off.
for x in range(stacklevel-1):
frame = _next_external_frame(frame)
if frame is None:
raise ValueError
except ValueError: except ValueError:
globals = sys.__dict__ globals = sys.__dict__
lineno = 1 lineno = 1
else: else:
globals = caller.f_globals globals = frame.f_globals
lineno = caller.f_lineno lineno = frame.f_lineno
if '__name__' in globals: if '__name__' in globals:
module = globals['__name__'] module = globals['__name__']
else: else:
@ -374,7 +398,6 @@ try:
defaultaction = _defaultaction defaultaction = _defaultaction
onceregistry = _onceregistry onceregistry = _onceregistry
_warnings_defaults = True _warnings_defaults = True
except ImportError: except ImportError:
filters = [] filters = []
defaultaction = "default" defaultaction = "default"

View file

@ -495,23 +495,10 @@ if os.environ.get("TERM"):
# #
if sys.platform[:3] == "win": if sys.platform[:3] == "win":
class WindowsDefault(BaseBrowser): class WindowsDefault(BaseBrowser):
# Windows Default opening arguments.
cmd = "start"
newwindow = ""
newtab = ""
def open(self, url, new=0, autoraise=True): def open(self, url, new=0, autoraise=True):
# Format the command for optional arguments and add the url.
if new == 1:
self.cmd += " " + self.newwindow
elif new == 2:
self.cmd += " " + self.newtab
self.cmd += " " + url
try: try:
subprocess.call(self.cmd, shell=True) os.startfile(url)
except OSError: except OSError:
# [Error 22] No application is associated with the specified # [Error 22] No application is associated with the specified
# file for this operation: '<URL>' # file for this operation: '<URL>'
@ -519,108 +506,19 @@ if sys.platform[:3] == "win":
else: else:
return True return True
# Windows Sub-Classes for commonly used browsers.
class InternetExplorer(WindowsDefault):
"""Launcher class for Internet Explorer browser"""
cmd = "start iexplore.exe"
newwindow = ""
newtab = ""
class WinChrome(WindowsDefault):
"""Launcher class for windows specific Google Chrome browser"""
cmd = "start chrome.exe"
newwindow = "-new-window"
newtab = "-new-tab"
class WinFirefox(WindowsDefault):
"""Launcher class for windows specific Firefox browser"""
cmd = "start firefox.exe"
newwindow = "-new-window"
newtab = "-new-tab"
class WinOpera(WindowsDefault):
"""Launcher class for windows specific Opera browser"""
cmd = "start opera"
newwindow = ""
newtab = ""
class WinSeaMonkey(WindowsDefault):
"""Launcher class for windows specific SeaMonkey browser"""
cmd = "start seamonkey"
newwinow = ""
newtab = ""
_tryorder = [] _tryorder = []
_browsers = {} _browsers = {}
# First try to use the default Windows browser. # First try to use the default Windows browser
register("windows-default", WindowsDefault) register("windows-default", WindowsDefault)
def find_windows_browsers(): # Detect some common Windows browsers, fallback to IE
""" Access the windows registry to determine iexplore = os.path.join(os.environ.get("PROGRAMFILES", "C:\\Program Files"),
what browsers are on the system. "Internet Explorer\\IEXPLORE.EXE")
""" for browser in ("firefox", "firebird", "seamonkey", "mozilla",
"netscape", "opera", iexplore):
import winreg if shutil.which(browser):
HKLM = winreg.HKEY_LOCAL_MACHINE register(browser, None, BackgroundBrowser(browser))
subkey = r'Software\Clients\StartMenuInternet'
read32 = winreg.KEY_READ | winreg.KEY_WOW64_32KEY
read64 = winreg.KEY_READ | winreg.KEY_WOW64_64KEY
key32 = winreg.OpenKey(HKLM, subkey, access=read32)
key64 = winreg.OpenKey(HKLM, subkey, access=read64)
# Return a list of browsers found in the registry
# Check if there are any different browsers in the
# 32 bit location instead of the 64 bit location.
browsers = []
i = 0
while True:
try:
browsers.append(winreg.EnumKey(key32, i))
except EnvironmentError:
break
i += 1
i = 0
while True:
try:
browsers.append(winreg.EnumKey(key64, i))
except EnvironmentError:
break
i += 1
winreg.CloseKey(key32)
winreg.CloseKey(key64)
return browsers
# Detect some common windows browsers
for browser in find_windows_browsers():
browser = browser.lower()
if "iexplore" in browser:
register("iexplore", None, InternetExplorer("iexplore"))
elif "chrome" in browser:
register("chrome", None, WinChrome("chrome"))
elif "firefox" in browser:
register("firefox", None, WinFirefox("firefox"))
elif "opera" in browser:
register("opera", None, WinOpera("opera"))
elif "seamonkey" in browser:
register("seamonkey", None, WinSeaMonkey("seamonkey"))
else:
register(browser, None, WindowsDefault(browser))
# #
# Platform support for MacOS # Platform support for MacOS

View file

@ -1,4 +1,4 @@
+++++++++++ +++++++++++
Python News Python News
+++++++++++ +++++++++++
@ -88,6 +88,9 @@ Release date: 2015-09-06
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #24305: Prevent import subsystem stack frames from being counted
by the warnings.warn(stacklevel=) parameter.
- Issue #24912: Prevent __class__ assignment to immutable built-in objects. - Issue #24912: Prevent __class__ assignment to immutable built-in objects.
- Issue #24975: Fix AST compilation for PEP 448 syntax. - Issue #24975: Fix AST compilation for PEP 448 syntax.
@ -95,9 +98,15 @@ Core and Builtins
Library Library
------- -------
- Issue #24917: time_strftime() buffer over-read.
- Issue #23144: Make sure that HTMLParser.feed() returns all the data, even - Issue #23144: Make sure that HTMLParser.feed() returns all the data, even
when convert_charrefs is True. when convert_charrefs is True.
- Issue #24748: To resolve a compatibility problem found with py2exe and
pywin32, imp.load_dynamic() once again ignores previously loaded modules
to support Python modules replacing themselves with extension modules.
Patch by Petr Viktorin.
- Issue #24635: Fixed a bug in typing.py where isinstance([], typing.Iterable) - Issue #24635: Fixed a bug in typing.py where isinstance([], typing.Iterable)
would return True once, then False on subsequent calls. would return True once, then False on subsequent calls.
@ -386,9 +395,6 @@ Library
- Issue #14373: C implementation of functools.lru_cache() now can be used with - Issue #14373: C implementation of functools.lru_cache() now can be used with
methods. methods.
- Issue #8232: webbrowser support incomplete on Windows. Patch by Brandon
Milam
- Issue #24347: Set KeyError if PyDict_GetItemWithError returns NULL. - Issue #24347: Set KeyError if PyDict_GetItemWithError returns NULL.
- Issue #24348: Drop superfluous incref/decref. - Issue #24348: Drop superfluous incref/decref.

View file

@ -582,3 +582,13 @@ PyInit__testmultiphase_exec_unreported_exception(PyObject *spec)
{ {
return PyModuleDef_Init(&def_exec_unreported_exception); return PyModuleDef_Init(&def_exec_unreported_exception);
} }
/*** Helper for imp test ***/
static PyModuleDef imp_dummy_def = TEST_MODULE_DEF("imp_dummy", main_slots, testexport_methods);
PyMODINIT_FUNC
PyInit_imp_dummy(PyObject *spec)
{
return PyModuleDef_Init(&imp_dummy_def);
}

View file

@ -610,14 +610,15 @@ time_strftime(PyObject *self, PyObject *args)
#if defined(MS_WINDOWS) && !defined(HAVE_WCSFTIME) #if defined(MS_WINDOWS) && !defined(HAVE_WCSFTIME)
/* check that the format string contains only valid directives */ /* check that the format string contains only valid directives */
for(outbuf = strchr(fmt, '%'); for (outbuf = strchr(fmt, '%');
outbuf != NULL; outbuf != NULL;
outbuf = strchr(outbuf+2, '%')) outbuf = strchr(outbuf+2, '%'))
{ {
if (outbuf[1]=='#') if (outbuf[1] == '#')
++outbuf; /* not documented by python, */ ++outbuf; /* not documented by python, */
if ((outbuf[1] == 'y') && buf.tm_year < 0) if (outbuf[1] == '\0')
{ break;
if ((outbuf[1] == 'y') && buf.tm_year < 0) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"format %y requires year >= 1900 on Windows"); "format %y requires year >= 1900 on Windows");
Py_DECREF(format); Py_DECREF(format);
@ -625,10 +626,12 @@ time_strftime(PyObject *self, PyObject *args)
} }
} }
#elif (defined(_AIX) || defined(sun)) && defined(HAVE_WCSFTIME) #elif (defined(_AIX) || defined(sun)) && defined(HAVE_WCSFTIME)
for(outbuf = wcschr(fmt, '%'); for (outbuf = wcschr(fmt, '%');
outbuf != NULL; outbuf != NULL;
outbuf = wcschr(outbuf+2, '%')) outbuf = wcschr(outbuf+2, '%'))
{ {
if (outbuf[1] == L'\0')
break;
/* Issue #19634: On AIX, wcsftime("y", (1899, 1, 1, 0, 0, 0, 0, 0, 0)) /* Issue #19634: On AIX, wcsftime("y", (1899, 1, 1, 0, 0, 0, 0, 0, 0))
returns "0/" instead of "99" */ returns "0/" instead of "99" */
if (outbuf[1] == L'y' && buf.tm_year < 0) { if (outbuf[1] == L'y' && buf.tm_year < 0) {
@ -659,7 +662,8 @@ time_strftime(PyObject *self, PyObject *args)
#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) #if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__)
err = errno; err = errno;
#endif #endif
if (buflen > 0 || i >= 256 * fmtlen) { if (buflen > 0 || fmtlen == 0 ||
(fmtlen > 4 && i >= 256 * fmtlen)) {
/* If the buffer is 256 times as long as the format, /* If the buffer is 256 times as long as the format,
it's probably not failing for lack of room! it's probably not failing for lack of room!
More likely, the format yields an empty result, More likely, the format yields an empty result,

View file

@ -513,6 +513,64 @@ warn_explicit(PyObject *category, PyObject *message,
return result; /* Py_None or NULL. */ return result; /* Py_None or NULL. */
} }
static int
is_internal_frame(PyFrameObject *frame)
{
static PyObject *importlib_string = NULL;
static PyObject *bootstrap_string = NULL;
PyObject *filename;
int contains;
if (importlib_string == NULL) {
importlib_string = PyUnicode_FromString("importlib");
if (importlib_string == NULL) {
return 0;
}
bootstrap_string = PyUnicode_FromString("_bootstrap");
if (bootstrap_string == NULL) {
Py_DECREF(importlib_string);
return 0;
}
Py_INCREF(importlib_string);
Py_INCREF(bootstrap_string);
}
if (frame == NULL || frame->f_code == NULL ||
frame->f_code->co_filename == NULL) {
return 0;
}
filename = frame->f_code->co_filename;
if (!PyUnicode_Check(filename)) {
return 0;
}
contains = PyUnicode_Contains(filename, importlib_string);
if (contains < 0) {
return 0;
}
else if (contains > 0) {
contains = PyUnicode_Contains(filename, bootstrap_string);
if (contains < 0) {
return 0;
}
else if (contains > 0) {
return 1;
}
}
return 0;
}
static PyFrameObject *
next_external_frame(PyFrameObject *frame)
{
do {
frame = frame->f_back;
} while (frame != NULL && is_internal_frame(frame));
return frame;
}
/* filename, module, and registry are new refs, globals is borrowed */ /* filename, module, and registry are new refs, globals is borrowed */
/* Returns 0 on error (no new refs), 1 on success */ /* Returns 0 on error (no new refs), 1 on success */
static int static int
@ -523,8 +581,18 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,
/* Setup globals and lineno. */ /* Setup globals and lineno. */
PyFrameObject *f = PyThreadState_GET()->frame; PyFrameObject *f = PyThreadState_GET()->frame;
while (--stack_level > 0 && f != NULL) // Stack level comparisons to Python code is off by one as there is no
// warnings-related stack level to avoid.
if (stack_level <= 0 || is_internal_frame(f)) {
while (--stack_level > 0 && f != NULL) {
f = f->f_back; f = f->f_back;
}
}
else {
while (--stack_level > 0 && f != NULL) {
f = next_external_frame(f);
}
}
if (f == NULL) { if (f == NULL) {
globals = PyThreadState_Get()->interp->sysdict; globals = PyThreadState_Get()->interp->sysdict;