Skip to content
This repository was archived by the owner on Feb 13, 2025. It is now read-only.

Commit a571371

Browse files
author
Anselm Kruis
committed
Merge branch master into master-slp
2 parents bb9ccc6 + 45fd951 commit a571371

14 files changed

+212
-141
lines changed

Lib/imp.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,12 @@ def load_dynamic(name, path, file=None):
334334
"""
335335
import importlib.machinery
336336
loader = importlib.machinery.ExtensionFileLoader(name, path)
337-
return loader.load_module()
337+
338+
# Issue #24748: Skip the sys.modules check in _load_module_shim;
339+
# always load new extension
340+
spec = importlib.machinery.ModuleSpec(
341+
name=name, loader=loader, origin=path)
342+
return _load(spec)
343+
338344
else:
339345
load_dynamic = None

Lib/test/imp_dummy.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Fodder for test of issue24748 in test_imp
2+
3+
dummy_name = True

Lib/test/test_imp.py

+24
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
except ImportError:
44
_thread = None
55
import importlib
6+
import importlib.util
67
import os
78
import os.path
89
import shutil
@@ -275,6 +276,29 @@ def test_load_module_extension_file_is_None(self):
275276
self.skipTest("found module doesn't appear to be a C extension")
276277
imp.load_module(name, None, *found[1:])
277278

279+
@requires_load_dynamic
280+
def test_issue24748_load_module_skips_sys_modules_check(self):
281+
name = 'test.imp_dummy'
282+
try:
283+
del sys.modules[name]
284+
except KeyError:
285+
pass
286+
try:
287+
module = importlib.import_module(name)
288+
spec = importlib.util.find_spec('_testmultiphase')
289+
module = imp.load_dynamic(name, spec.origin)
290+
self.assertEqual(module.__name__, name)
291+
self.assertEqual(module.__spec__.name, name)
292+
self.assertEqual(module.__spec__.origin, spec.origin)
293+
self.assertRaises(AttributeError, getattr, module, 'dummy_name')
294+
self.assertEqual(module.int_const, 1969)
295+
self.assertIs(sys.modules[name], module)
296+
finally:
297+
try:
298+
del sys.modules[name]
299+
except KeyError:
300+
pass
301+
278302
@unittest.skipIf(sys.dont_write_bytecode,
279303
"test meaningful only when writing bytecode")
280304
def test_bug7732(self):

Lib/test/test_time.py

+13
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,19 @@ def _bounds_checking(self, func):
177177
def test_strftime_bounding_check(self):
178178
self._bounds_checking(lambda tup: time.strftime('', tup))
179179

180+
def test_strftime_format_check(self):
181+
# Test that strftime does not crash on invalid format strings
182+
# that may trigger a buffer overread. When not triggered,
183+
# strftime may succeed or raise ValueError depending on
184+
# the platform.
185+
for x in [ '', 'A', '%A', '%AA' ]:
186+
for y in range(0x0, 0x10):
187+
for z in [ '%', 'A%', 'AA%', '%A%', 'A%A%', '%#' ]:
188+
try:
189+
time.strftime(x * y + z)
190+
except ValueError:
191+
pass
192+
180193
def test_default_values_for_zero(self):
181194
# Make sure that using all zeros uses the proper default
182195
# values. No test for daylight savings since strftime() does

Lib/test/test_warnings.py renamed to Lib/test/test_warnings/__init__.py

+21-10
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from test import support
88
from test.support.script_helper import assert_python_ok, assert_python_failure
99

10-
from test import warning_tests
10+
from test.test_warnings.data import stacklevel as warning_tests
1111

1212
import warnings as original_warnings
1313

@@ -194,11 +194,11 @@ def test_once(self):
194194
self.module.resetwarnings()
195195
self.module.filterwarnings("once", category=UserWarning)
196196
message = UserWarning("FilterTests.test_once")
197-
self.module.warn_explicit(message, UserWarning, "test_warnings.py",
197+
self.module.warn_explicit(message, UserWarning, "__init__.py",
198198
42)
199199
self.assertEqual(w[-1].message, message)
200200
del w[:]
201-
self.module.warn_explicit(message, UserWarning, "test_warnings.py",
201+
self.module.warn_explicit(message, UserWarning, "__init__.py",
202202
13)
203203
self.assertEqual(len(w), 0)
204204
self.module.warn_explicit(message, UserWarning, "test_warnings2.py",
@@ -304,10 +304,10 @@ def test_filename(self):
304304
module=self.module) as w:
305305
warning_tests.inner("spam1")
306306
self.assertEqual(os.path.basename(w[-1].filename),
307-
"warning_tests.py")
307+
"stacklevel.py")
308308
warning_tests.outer("spam2")
309309
self.assertEqual(os.path.basename(w[-1].filename),
310-
"warning_tests.py")
310+
"stacklevel.py")
311311

312312
def test_stacklevel(self):
313313
# Test stacklevel argument
@@ -317,25 +317,36 @@ def test_stacklevel(self):
317317
module=self.module) as w:
318318
warning_tests.inner("spam3", stacklevel=1)
319319
self.assertEqual(os.path.basename(w[-1].filename),
320-
"warning_tests.py")
320+
"stacklevel.py")
321321
warning_tests.outer("spam4", stacklevel=1)
322322
self.assertEqual(os.path.basename(w[-1].filename),
323-
"warning_tests.py")
323+
"stacklevel.py")
324324

325325
warning_tests.inner("spam5", stacklevel=2)
326326
self.assertEqual(os.path.basename(w[-1].filename),
327-
"test_warnings.py")
327+
"__init__.py")
328328
warning_tests.outer("spam6", stacklevel=2)
329329
self.assertEqual(os.path.basename(w[-1].filename),
330-
"warning_tests.py")
330+
"stacklevel.py")
331331
warning_tests.outer("spam6.5", stacklevel=3)
332332
self.assertEqual(os.path.basename(w[-1].filename),
333-
"test_warnings.py")
333+
"__init__.py")
334334

335335
warning_tests.inner("spam7", stacklevel=9999)
336336
self.assertEqual(os.path.basename(w[-1].filename),
337337
"sys")
338338

339+
def test_stacklevel_import(self):
340+
# Issue #24305: With stacklevel=2, module-level warnings should work.
341+
support.unload('test.test_warnings.data.import_warning')
342+
with warnings_state(self.module):
343+
with original_warnings.catch_warnings(record=True,
344+
module=self.module) as w:
345+
self.module.simplefilter('always')
346+
import test.test_warnings.data.import_warning
347+
self.assertEqual(len(w), 1)
348+
self.assertEqual(w[0].filename, __file__)
349+
339350
def test_missing_filename_not_main(self):
340351
# If __file__ is not specified and __main__ is not the module name,
341352
# then __file__ should be set to the module name.

Lib/test/test_warnings/__main__.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import unittest
2+
3+
unittest.main('test.test_warnings')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import warnings
2+
3+
warnings.warn('module-level warning', DeprecationWarning, stacklevel=2)
File renamed without changes.

Lib/warnings.py

+27-4
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,20 @@ def _getcategory(category):
160160
return cat
161161

162162

163+
def _is_internal_frame(frame):
164+
"""Signal whether the frame is an internal CPython implementation detail."""
165+
filename = frame.f_code.co_filename
166+
return 'importlib' in filename and '_bootstrap' in filename
167+
168+
169+
def _next_external_frame(frame):
170+
"""Find the next frame that doesn't involve CPython internals."""
171+
frame = frame.f_back
172+
while frame is not None and _is_internal_frame(frame):
173+
frame = frame.f_back
174+
return frame
175+
176+
163177
# Code typically replaced by _warnings
164178
def warn(message, category=None, stacklevel=1):
165179
"""Issue a warning, or maybe ignore it or raise an exception."""
@@ -174,13 +188,23 @@ def warn(message, category=None, stacklevel=1):
174188
"not '{:s}'".format(type(category).__name__))
175189
# Get context information
176190
try:
177-
caller = sys._getframe(stacklevel)
191+
if stacklevel <= 1 or _is_internal_frame(sys._getframe(1)):
192+
# If frame is too small to care or if the warning originated in
193+
# internal code, then do not try to hide any frames.
194+
frame = sys._getframe(stacklevel)
195+
else:
196+
frame = sys._getframe(1)
197+
# Look for one frame less since the above line starts us off.
198+
for x in range(stacklevel-1):
199+
frame = _next_external_frame(frame)
200+
if frame is None:
201+
raise ValueError
178202
except ValueError:
179203
globals = sys.__dict__
180204
lineno = 1
181205
else:
182-
globals = caller.f_globals
183-
lineno = caller.f_lineno
206+
globals = frame.f_globals
207+
lineno = frame.f_lineno
184208
if '__name__' in globals:
185209
module = globals['__name__']
186210
else:
@@ -374,7 +398,6 @@ def __exit__(self, *exc_info):
374398
defaultaction = _defaultaction
375399
onceregistry = _onceregistry
376400
_warnings_defaults = True
377-
378401
except ImportError:
379402
filters = []
380403
defaultaction = "default"

Lib/webbrowser.py

+9-111
Original file line numberDiff line numberDiff line change
@@ -495,132 +495,30 @@ def register_X_browsers():
495495
#
496496

497497
if sys.platform[:3] == "win":
498-
499498
class WindowsDefault(BaseBrowser):
500-
# Windows Default opening arguments.
501-
502-
cmd = "start"
503-
newwindow = ""
504-
newtab = ""
505-
506499
def open(self, url, new=0, autoraise=True):
507-
# Format the command for optional arguments and add the url.
508-
if new == 1:
509-
self.cmd += " " + self.newwindow
510-
elif new == 2:
511-
self.cmd += " " + self.newtab
512-
self.cmd += " " + url
513500
try:
514-
subprocess.call(self.cmd, shell=True)
501+
os.startfile(url)
515502
except OSError:
516503
# [Error 22] No application is associated with the specified
517504
# file for this operation: '<URL>'
518505
return False
519506
else:
520507
return True
521508

522-
523-
# Windows Sub-Classes for commonly used browsers.
524-
525-
class InternetExplorer(WindowsDefault):
526-
"""Launcher class for Internet Explorer browser"""
527-
528-
cmd = "start iexplore.exe"
529-
newwindow = ""
530-
newtab = ""
531-
532-
533-
class WinChrome(WindowsDefault):
534-
"""Launcher class for windows specific Google Chrome browser"""
535-
536-
cmd = "start chrome.exe"
537-
newwindow = "-new-window"
538-
newtab = "-new-tab"
539-
540-
541-
class WinFirefox(WindowsDefault):
542-
"""Launcher class for windows specific Firefox browser"""
543-
544-
cmd = "start firefox.exe"
545-
newwindow = "-new-window"
546-
newtab = "-new-tab"
547-
548-
549-
class WinOpera(WindowsDefault):
550-
"""Launcher class for windows specific Opera browser"""
551-
552-
cmd = "start opera"
553-
newwindow = ""
554-
newtab = ""
555-
556-
557-
class WinSeaMonkey(WindowsDefault):
558-
"""Launcher class for windows specific SeaMonkey browser"""
559-
560-
cmd = "start seamonkey"
561-
newwinow = ""
562-
newtab = ""
563-
564-
565509
_tryorder = []
566510
_browsers = {}
567511

568-
# First try to use the default Windows browser.
512+
# First try to use the default Windows browser
569513
register("windows-default", WindowsDefault)
570514

571-
def find_windows_browsers():
572-
""" Access the windows registry to determine
573-
what browsers are on the system.
574-
"""
575-
576-
import winreg
577-
HKLM = winreg.HKEY_LOCAL_MACHINE
578-
subkey = r'Software\Clients\StartMenuInternet'
579-
read32 = winreg.KEY_READ | winreg.KEY_WOW64_32KEY
580-
read64 = winreg.KEY_READ | winreg.KEY_WOW64_64KEY
581-
key32 = winreg.OpenKey(HKLM, subkey, access=read32)
582-
key64 = winreg.OpenKey(HKLM, subkey, access=read64)
583-
584-
# Return a list of browsers found in the registry
585-
# Check if there are any different browsers in the
586-
# 32 bit location instead of the 64 bit location.
587-
browsers = []
588-
i = 0
589-
while True:
590-
try:
591-
browsers.append(winreg.EnumKey(key32, i))
592-
except EnvironmentError:
593-
break
594-
i += 1
595-
596-
i = 0
597-
while True:
598-
try:
599-
browsers.append(winreg.EnumKey(key64, i))
600-
except EnvironmentError:
601-
break
602-
i += 1
603-
604-
winreg.CloseKey(key32)
605-
winreg.CloseKey(key64)
606-
607-
return browsers
608-
609-
# Detect some common windows browsers
610-
for browser in find_windows_browsers():
611-
browser = browser.lower()
612-
if "iexplore" in browser:
613-
register("iexplore", None, InternetExplorer("iexplore"))
614-
elif "chrome" in browser:
615-
register("chrome", None, WinChrome("chrome"))
616-
elif "firefox" in browser:
617-
register("firefox", None, WinFirefox("firefox"))
618-
elif "opera" in browser:
619-
register("opera", None, WinOpera("opera"))
620-
elif "seamonkey" in browser:
621-
register("seamonkey", None, WinSeaMonkey("seamonkey"))
622-
else:
623-
register(browser, None, WindowsDefault(browser))
515+
# Detect some common Windows browsers, fallback to IE
516+
iexplore = os.path.join(os.environ.get("PROGRAMFILES", "C:\\Program Files"),
517+
"Internet Explorer\\IEXPLORE.EXE")
518+
for browser in ("firefox", "firebird", "seamonkey", "mozilla",
519+
"netscape", "opera", iexplore):
520+
if shutil.which(browser):
521+
register(browser, None, BackgroundBrowser(browser))
624522

625523
#
626524
# Platform support for MacOS

0 commit comments

Comments
 (0)