diff options
Diffstat (limited to 'Lib')
| -rw-r--r-- | Lib/imp.py | 8 | ||||
| -rw-r--r-- | Lib/test/imp_dummy.py | 3 | ||||
| -rw-r--r-- | Lib/test/test_imp.py | 24 | ||||
| -rw-r--r-- | Lib/test/test_time.py | 13 | ||||
| -rw-r--r-- | Lib/test/test_warnings/__init__.py (renamed from Lib/test/test_warnings.py) | 37 | ||||
| -rw-r--r-- | Lib/test/test_warnings/__main__.py | 3 | ||||
| -rw-r--r-- | Lib/test/test_warnings/data/import_warning.py | 3 | ||||
| -rw-r--r-- | Lib/test/test_warnings/data/stacklevel.py (renamed from Lib/test/warning_tests.py) | 0 | ||||
| -rw-r--r-- | Lib/warnings.py | 31 | ||||
| -rwxr-xr-x | Lib/webbrowser.py | 120 |
10 files changed, 110 insertions, 132 deletions
@@ -334,6 +334,12 @@ if create_dynamic: """ import importlib.machinery 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: load_dynamic = None diff --git a/Lib/test/imp_dummy.py b/Lib/test/imp_dummy.py new file mode 100644 index 0000000..2a4deb4 --- /dev/null +++ b/Lib/test/imp_dummy.py @@ -0,0 +1,3 @@ +# Fodder for test of issue24748 in test_imp + +dummy_name = True diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py index 47bf1de..ee9ee1a 100644 --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -3,6 +3,7 @@ try: except ImportError: _thread = None import importlib +import importlib.util import os import os.path import shutil @@ -275,6 +276,29 @@ class ImportTests(unittest.TestCase): self.skipTest("found module doesn't appear to be a C extension") 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, "test meaningful only when writing bytecode") def test_bug7732(self): diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index 6334e02..6bcd212 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -174,6 +174,19 @@ class TimeTestCase(unittest.TestCase): def test_strftime_bounding_check(self): 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): # Make sure that using all zeros uses the proper default # values. No test for daylight savings since strftime() does diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings/__init__.py index 03d9958..991a249 100644 --- a/Lib/test/test_warnings.py +++ b/Lib/test/test_warnings/__init__.py @@ -7,7 +7,7 @@ import unittest from test import support 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 @@ -44,7 +44,6 @@ class BaseTest: """Basic bookkeeping required for testing.""" def setUp(self): - self.old_unittest_module = unittest.case.warnings # The __warningregistry__ needs to be in a pristine state for tests # to work properly. if '__warningregistry__' in globals(): @@ -56,15 +55,10 @@ class BaseTest: # The 'warnings' module must be explicitly set so that the proper # interaction between _warnings and 'warnings' can be controlled. 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() def tearDown(self): sys.modules['warnings'] = original_warnings - unittest.case.warnings = self.old_unittest_module super(BaseTest, self).tearDown() class PublicAPITests(BaseTest): @@ -194,11 +188,11 @@ class FilterTests(BaseTest): self.module.resetwarnings() self.module.filterwarnings("once", category=UserWarning) message = UserWarning("FilterTests.test_once") - self.module.warn_explicit(message, UserWarning, "test_warnings.py", + self.module.warn_explicit(message, UserWarning, "__init__.py", 42) self.assertEqual(w[-1].message, message) del w[:] - self.module.warn_explicit(message, UserWarning, "test_warnings.py", + self.module.warn_explicit(message, UserWarning, "__init__.py", 13) self.assertEqual(len(w), 0) self.module.warn_explicit(message, UserWarning, "test_warnings2.py", @@ -304,10 +298,10 @@ class WarnTests(BaseTest): module=self.module) as w: warning_tests.inner("spam1") self.assertEqual(os.path.basename(w[-1].filename), - "warning_tests.py") + "stacklevel.py") warning_tests.outer("spam2") self.assertEqual(os.path.basename(w[-1].filename), - "warning_tests.py") + "stacklevel.py") def test_stacklevel(self): # Test stacklevel argument @@ -317,25 +311,36 @@ class WarnTests(BaseTest): module=self.module) as w: warning_tests.inner("spam3", stacklevel=1) self.assertEqual(os.path.basename(w[-1].filename), - "warning_tests.py") + "stacklevel.py") warning_tests.outer("spam4", stacklevel=1) self.assertEqual(os.path.basename(w[-1].filename), - "warning_tests.py") + "stacklevel.py") warning_tests.inner("spam5", stacklevel=2) self.assertEqual(os.path.basename(w[-1].filename), - "test_warnings.py") + "__init__.py") warning_tests.outer("spam6", stacklevel=2) self.assertEqual(os.path.basename(w[-1].filename), - "warning_tests.py") + "stacklevel.py") warning_tests.outer("spam6.5", stacklevel=3) self.assertEqual(os.path.basename(w[-1].filename), - "test_warnings.py") + "__init__.py") warning_tests.inner("spam7", stacklevel=9999) self.assertEqual(os.path.basename(w[-1].filename), "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): # If __file__ is not specified and __main__ is not the module name, # then __file__ should be set to the module name. diff --git a/Lib/test/test_warnings/__main__.py b/Lib/test/test_warnings/__main__.py new file mode 100644 index 0000000..44e52ec --- /dev/null +++ b/Lib/test/test_warnings/__main__.py @@ -0,0 +1,3 @@ +import unittest + +unittest.main('test.test_warnings') diff --git a/Lib/test/test_warnings/data/import_warning.py b/Lib/test/test_warnings/data/import_warning.py new file mode 100644 index 0000000..d6ea2ce --- /dev/null +++ b/Lib/test/test_warnings/data/import_warning.py @@ -0,0 +1,3 @@ +import warnings + +warnings.warn('module-level warning', DeprecationWarning, stacklevel=2)
\ No newline at end of file diff --git a/Lib/test/warning_tests.py b/Lib/test/test_warnings/data/stacklevel.py index d0519ef..d0519ef 100644 --- a/Lib/test/warning_tests.py +++ b/Lib/test/test_warnings/data/stacklevel.py diff --git a/Lib/warnings.py b/Lib/warnings.py index 16246b4..1d4fb20 100644 --- a/Lib/warnings.py +++ b/Lib/warnings.py @@ -160,6 +160,20 @@ def _getcategory(category): 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 def warn(message, category=None, stacklevel=1): """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__)) # Get context information 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: globals = sys.__dict__ lineno = 1 else: - globals = caller.f_globals - lineno = caller.f_lineno + globals = frame.f_globals + lineno = frame.f_lineno if '__name__' in globals: module = globals['__name__'] else: @@ -374,7 +398,6 @@ try: defaultaction = _defaultaction onceregistry = _onceregistry _warnings_defaults = True - except ImportError: filters = [] defaultaction = "default" diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py index 6deed92..845f1d0 100755 --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -495,23 +495,10 @@ if os.environ.get("TERM"): # if sys.platform[:3] == "win": - class WindowsDefault(BaseBrowser): - # Windows Default opening arguments. - - cmd = "start" - newwindow = "" - newtab = "" - 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: - subprocess.call(self.cmd, shell=True) + os.startfile(url) except OSError: # [Error 22] No application is associated with the specified # file for this operation: '<URL>' @@ -519,108 +506,19 @@ if sys.platform[:3] == "win": else: 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 = [] _browsers = {} - # First try to use the default Windows browser. + # First try to use the default Windows browser register("windows-default", WindowsDefault) - def find_windows_browsers(): - """ Access the windows registry to determine - what browsers are on the system. - """ - - import winreg - HKLM = winreg.HKEY_LOCAL_MACHINE - 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)) + # Detect some common Windows browsers, fallback to IE + iexplore = os.path.join(os.environ.get("PROGRAMFILES", "C:\\Program Files"), + "Internet Explorer\\IEXPLORE.EXE") + for browser in ("firefox", "firebird", "seamonkey", "mozilla", + "netscape", "opera", iexplore): + if shutil.which(browser): + register(browser, None, BackgroundBrowser(browser)) # # Platform support for MacOS |
