mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 11:49:12 +00:00 
			
		
		
		
	Issue #18351: Fix various issues with
importlib._bootstrap._get_sourcefile(). Thanks to its only use by the C API, it was never properly tested until now. Thanks to Neal Norwitz for discovering the bug and Madison May for the patch.
This commit is contained in:
		
							parent
							
								
									2a99d5df63
								
							
						
					
					
						commit
						a53cca3fea
					
				
					 5 changed files with 3446 additions and 3407 deletions
				
			
		| 
						 | 
					@ -471,16 +471,14 @@ def _get_sourcefile(bytecode_path):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    if len(bytecode_path) == 0:
 | 
					    if len(bytecode_path) == 0:
 | 
				
			||||||
        return None
 | 
					        return None
 | 
				
			||||||
    rest, _, extension = bytecode_path.rparition('.')
 | 
					    rest, _, extension = bytecode_path.rpartition('.')
 | 
				
			||||||
    if not rest or extension.lower()[-3:-1] != '.py':
 | 
					    if not rest or extension.lower()[-3:-1] != 'py':
 | 
				
			||||||
        return bytecode_path
 | 
					        return bytecode_path
 | 
				
			||||||
 | 
					 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        source_path = source_from_cache(bytecode_path)
 | 
					        source_path = source_from_cache(bytecode_path)
 | 
				
			||||||
    except (NotImplementedError, ValueError):
 | 
					    except (NotImplementedError, ValueError):
 | 
				
			||||||
        source_path = bytcode_path[-1:]
 | 
					        source_path = bytecode_path[:-1]
 | 
				
			||||||
 | 
					    return source_path if _path_isfile(source_path) else bytecode_path
 | 
				
			||||||
    return source_path if _path_isfile(source_stats) else bytecode_path
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _verbose_message(message, *args, verbosity=1):
 | 
					def _verbose_message(message, *args, verbosity=1):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
# We import importlib *ASAP* in order to test #15386
 | 
					# We import importlib *ASAP* in order to test #15386
 | 
				
			||||||
import importlib
 | 
					import importlib
 | 
				
			||||||
 | 
					from importlib._bootstrap import _get_sourcefile
 | 
				
			||||||
import builtins
 | 
					import builtins
 | 
				
			||||||
import imp
 | 
					import imp
 | 
				
			||||||
from test.test_importlib.import_ import util as importlib_util
 | 
					from test.test_importlib.import_ import util as importlib_util
 | 
				
			||||||
| 
						 | 
					@ -11,6 +12,7 @@ import random
 | 
				
			||||||
import stat
 | 
					import stat
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
import unittest
 | 
					import unittest
 | 
				
			||||||
 | 
					import unittest.mock as mock
 | 
				
			||||||
import textwrap
 | 
					import textwrap
 | 
				
			||||||
import errno
 | 
					import errno
 | 
				
			||||||
import shutil
 | 
					import shutil
 | 
				
			||||||
| 
						 | 
					@ -864,6 +866,40 @@ class ImportlibBootstrapTests(unittest.TestCase):
 | 
				
			||||||
        self.assertIs(imp.new_module, mod.new_module)
 | 
					        self.assertIs(imp.new_module, mod.new_module)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@cpython_only
 | 
				
			||||||
 | 
					class GetSourcefileTests(unittest.TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """Test importlib._bootstrap._get_sourcefile() as used by the C API.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Because of the peculiarities of the need of this function, the tests are
 | 
				
			||||||
 | 
					    knowingly whitebox tests.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_get_sourcefile(self):
 | 
				
			||||||
 | 
					        # Given a valid bytecode path, return the path to the corresponding
 | 
				
			||||||
 | 
					        # source file if it exists.
 | 
				
			||||||
 | 
					        with mock.patch('importlib._bootstrap._path_isfile') as _path_isfile:
 | 
				
			||||||
 | 
					            _path_isfile.return_value = True;
 | 
				
			||||||
 | 
					            path = TESTFN + '.pyc'
 | 
				
			||||||
 | 
					            expect = TESTFN + '.py'
 | 
				
			||||||
 | 
					            self.assertEqual(_get_sourcefile(path), expect)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_get_sourcefile_no_source(self):
 | 
				
			||||||
 | 
					        # Given a valid bytecode path without a corresponding source path,
 | 
				
			||||||
 | 
					        # return the original bytecode path.
 | 
				
			||||||
 | 
					        with mock.patch('importlib._bootstrap._path_isfile') as _path_isfile:
 | 
				
			||||||
 | 
					            _path_isfile.return_value = False;
 | 
				
			||||||
 | 
					            path = TESTFN + '.pyc'
 | 
				
			||||||
 | 
					            self.assertEqual(_get_sourcefile(path), path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_get_sourcefile_bad_ext(self):
 | 
				
			||||||
 | 
					        # Given a path with an invalid bytecode extension, return the
 | 
				
			||||||
 | 
					        # bytecode path passed as the argument.
 | 
				
			||||||
 | 
					        path = TESTFN + '.bad_ext'
 | 
				
			||||||
 | 
					        self.assertEqual(_get_sourcefile(path), path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ImportTracebackTests(unittest.TestCase):
 | 
					class ImportTracebackTests(unittest.TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
| 
						 | 
					@ -1028,7 +1064,7 @@ def test_main(verbose=None):
 | 
				
			||||||
    run_unittest(ImportTests, PycacheTests, FilePermissionTests,
 | 
					    run_unittest(ImportTests, PycacheTests, FilePermissionTests,
 | 
				
			||||||
                 PycRewritingTests, PathsTests, RelativeImportTests,
 | 
					                 PycRewritingTests, PathsTests, RelativeImportTests,
 | 
				
			||||||
                 OverridingImportBuiltinTests,
 | 
					                 OverridingImportBuiltinTests,
 | 
				
			||||||
                 ImportlibBootstrapTests,
 | 
					                 ImportlibBootstrapTests, GetSourcefileTests,
 | 
				
			||||||
                 TestSymbolicallyLinkedPackage,
 | 
					                 TestSymbolicallyLinkedPackage,
 | 
				
			||||||
                 ImportTracebackTests)
 | 
					                 ImportTracebackTests)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -788,6 +788,7 @@ Laura Matson
 | 
				
			||||||
Graham Matthews
 | 
					Graham Matthews
 | 
				
			||||||
Dieter Maurer
 | 
					Dieter Maurer
 | 
				
			||||||
Daniel May
 | 
					Daniel May
 | 
				
			||||||
 | 
					Madison May
 | 
				
			||||||
Arnaud Mazin
 | 
					Arnaud Mazin
 | 
				
			||||||
Rebecca McCreary
 | 
					Rebecca McCreary
 | 
				
			||||||
Kirk McDonald
 | 
					Kirk McDonald
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -130,6 +130,12 @@ Library
 | 
				
			||||||
- Issue #18113: Fixed a refcount leak in the curses.panel module's
 | 
					- Issue #18113: Fixed a refcount leak in the curses.panel module's
 | 
				
			||||||
  set_userptr() method.  Reported by Atsuo Ishimoto.
 | 
					  set_userptr() method.  Reported by Atsuo Ishimoto.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					C API
 | 
				
			||||||
 | 
					-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Issue #18351: Fix various issues with a helper function in importlib used
 | 
				
			||||||
 | 
					  by PyImport_ExecCodeModuleWithPathnames() (and thus by extension PyImport_ExecCodeModule() and PyImport_ExecCodeModuleEx()).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
IDLE
 | 
					IDLE
 | 
				
			||||||
----
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										6798
									
								
								Python/importlib.h
									
										
									
									
									
								
							
							
						
						
									
										6798
									
								
								Python/importlib.h
									
										
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue