mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	Issue #18076: Introduce imoportlib.util.decode_source().
The helper function makes it easier to implement imoprtlib.abc.InspectLoader.get_source() by making that function require just the raw bytes for source code and handling all other details.
This commit is contained in:
		
							parent
							
								
									f4375ef4d4
								
							
						
					
					
						commit
						f24fecd4ac
					
				
					 6 changed files with 3629 additions and 3572 deletions
				
			
		|  | @ -916,6 +916,14 @@ an :term:`importer`. | ||||||
| 
 | 
 | ||||||
|    .. versionadded:: 3.4 |    .. versionadded:: 3.4 | ||||||
| 
 | 
 | ||||||
|  | .. function:: decode_source(source_bytes) | ||||||
|  | 
 | ||||||
|  |    Decode the given bytes representing source code and return it as a string | ||||||
|  |    with universal newlines (as required by | ||||||
|  |    :meth:`importlib.abc.InspectLoader.get_source`). | ||||||
|  | 
 | ||||||
|  |    .. versionadded:: 3.4 | ||||||
|  | 
 | ||||||
| .. function:: resolve_name(name, package) | .. function:: resolve_name(name, package) | ||||||
| 
 | 
 | ||||||
|    Resolve a relative module name to an absolute one. |    Resolve a relative module name to an absolute one. | ||||||
|  |  | ||||||
|  | @ -723,6 +723,18 @@ def _code_to_bytecode(code, mtime=0, source_size=0): | ||||||
|     return data |     return data | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | def decode_source(source_bytes): | ||||||
|  |     """Decode bytes representing source code and return the string. | ||||||
|  | 
 | ||||||
|  |     Universal newline support is used in the decoding. | ||||||
|  |     """ | ||||||
|  |     import tokenize  # To avoid bootstrap issues. | ||||||
|  |     source_bytes_readline = _io.BytesIO(source_bytes).readline | ||||||
|  |     encoding = tokenize.detect_encoding(source_bytes_readline) | ||||||
|  |     newline_decoder = _io.IncrementalNewlineDecoder(None, True) | ||||||
|  |     return newline_decoder.decode(source_bytes.decode(encoding[0])) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| # Loaders ##################################################################### | # Loaders ##################################################################### | ||||||
| 
 | 
 | ||||||
| class BuiltinImporter: | class BuiltinImporter: | ||||||
|  | @ -965,11 +977,7 @@ def get_source(self, fullname): | ||||||
|         except OSError as exc: |         except OSError as exc: | ||||||
|             raise ImportError("source not available through get_data()", |             raise ImportError("source not available through get_data()", | ||||||
|                               name=fullname) from exc |                               name=fullname) from exc | ||||||
|         import tokenize |         return decode_source(source_bytes) | ||||||
|         readsource = _io.BytesIO(source_bytes).readline |  | ||||||
|         encoding = tokenize.detect_encoding(readsource) |  | ||||||
|         newline_decoder = _io.IncrementalNewlineDecoder(None, True) |  | ||||||
|         return newline_decoder.decode(source_bytes.decode(encoding[0])) |  | ||||||
| 
 | 
 | ||||||
|     def source_to_code(self, data, path, *, _optimize=-1): |     def source_to_code(self, data, path, *, _optimize=-1): | ||||||
|         """Return the code object compiled from source. |         """Return the code object compiled from source. | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| from ._bootstrap import MAGIC_NUMBER | from ._bootstrap import MAGIC_NUMBER | ||||||
| from ._bootstrap import cache_from_source | from ._bootstrap import cache_from_source | ||||||
|  | from ._bootstrap import decode_source | ||||||
| from ._bootstrap import module_to_load | from ._bootstrap import module_to_load | ||||||
| from ._bootstrap import set_loader | from ._bootstrap import set_loader | ||||||
| from ._bootstrap import set_package | from ._bootstrap import set_package | ||||||
|  |  | ||||||
|  | @ -9,6 +9,27 @@ | ||||||
| import warnings | import warnings | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class DecodeSourceBytesTests(unittest.TestCase): | ||||||
|  | 
 | ||||||
|  |     source = "string ='ü'" | ||||||
|  | 
 | ||||||
|  |     def test_ut8_default(self): | ||||||
|  |         source_bytes = self.source.encode('utf-8') | ||||||
|  |         self.assertEqual(util.decode_source(source_bytes), self.source) | ||||||
|  | 
 | ||||||
|  |     def test_specified_encoding(self): | ||||||
|  |         source = '# coding=latin-1\n' + self.source | ||||||
|  |         source_bytes = source.encode('latin-1') | ||||||
|  |         assert source_bytes != source.encode('utf-8') | ||||||
|  |         self.assertEqual(util.decode_source(source_bytes), source) | ||||||
|  | 
 | ||||||
|  |     def test_universal_newlines(self): | ||||||
|  |         source = '\r\n'.join([self.source, self.source]) | ||||||
|  |         source_bytes = source.encode('utf-8') | ||||||
|  |         self.assertEqual(util.decode_source(source_bytes), | ||||||
|  |                          '\n'.join([self.source, self.source])) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class ModuleToLoadTests(unittest.TestCase): | class ModuleToLoadTests(unittest.TestCase): | ||||||
| 
 | 
 | ||||||
|     module_name = 'ModuleManagerTest_module' |     module_name = 'ModuleManagerTest_module' | ||||||
|  |  | ||||||
|  | @ -123,6 +123,8 @@ Core and Builtins | ||||||
| Library | Library | ||||||
| ------- | ------- | ||||||
| 
 | 
 | ||||||
|  | - Issue #18076: Introduce importlib.util.decode_source(). | ||||||
|  | 
 | ||||||
| - importlib.abc.SourceLoader.get_source() no longer changes SyntaxError or | - importlib.abc.SourceLoader.get_source() no longer changes SyntaxError or | ||||||
|   UnicodeDecodeError into ImportError. |   UnicodeDecodeError into ImportError. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										7151
									
								
								Python/importlib.h
									
										
									
									
									
								
							
							
						
						
									
										7151
									
								
								Python/importlib.h
									
										
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Brett Cannon
						Brett Cannon