Skip to content

Commit fd07415

Browse files
committed
Issue python#2377: Make importlib the implementation of __import__().
importlib._bootstrap is now frozen into Python/importlib.h and stored as _frozen_importlib in sys.modules. Py_Initialize() loads the frozen code along with sys and imp and then uses _frozen_importlib._install() to set builtins.__import__() w/ _frozen_importlib.__import__().
1 parent d2cbd90 commit fd07415

38 files changed

+3597
-599
lines changed

Include/abstract.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,10 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
339339

340340
PyAPI_FUNC(PyObject *) PyObject_CallMethodObjArgs(PyObject *o,
341341
PyObject *method, ...);
342+
PyAPI_FUNC(PyObject *) _PyObject_CallMethodObjIdArgs(PyObject *o,
343+
struct _Py_Identifier *method,
344+
...);
345+
342346

343347
/*
344348
Call the method named m of object o with a variable number of

Include/dictobject.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ PyAPI_DATA(PyTypeObject) PyDictValues_Type;
109109
PyAPI_FUNC(PyObject *) PyDict_New(void);
110110
PyAPI_FUNC(PyObject *) PyDict_GetItem(PyObject *mp, PyObject *key);
111111
PyAPI_FUNC(PyObject *) PyDict_GetItemWithError(PyObject *mp, PyObject *key);
112+
PyAPI_FUNC(PyObject *) _PyDict_GetItemIdWithError(PyObject *dp,
113+
struct _Py_Identifier *key);
112114
PyAPI_FUNC(int) PyDict_SetItem(PyObject *mp, PyObject *key, PyObject *item);
113115
PyAPI_FUNC(int) PyDict_DelItem(PyObject *mp, PyObject *key);
114116
PyAPI_FUNC(void) PyDict_Clear(PyObject *mp);

Include/import.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
extern "C" {
88
#endif
99

10+
PyAPI_FUNC(void) _PyImportZip_Init(void);
11+
12+
PyMODINIT_FUNC PyInit_imp(void);
1013
PyAPI_FUNC(long) PyImport_GetMagicNumber(void);
1114
PyAPI_FUNC(const char *) PyImport_GetMagicTag(void);
1215
PyAPI_FUNC(PyObject *) PyImport_ExecCodeModule(

Include/pystate.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ typedef struct _is {
2525
PyObject *modules_by_index;
2626
PyObject *sysdict;
2727
PyObject *builtins;
28+
PyObject *importlib;
2829
PyObject *modules_reloading;
2930

3031
PyObject *codec_search_path;
@@ -33,6 +34,7 @@ typedef struct _is {
3334
int codecs_initialized;
3435
int fscodec_initialized;
3536

37+
3638
#ifdef HAVE_DLOPEN
3739
int dlopenflags;
3840
#endif

Include/pythonrun.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ PyAPI_FUNC(const char *) _Py_hgversion(void);
188188
PyAPI_FUNC(PyObject *) _PyBuiltin_Init(void);
189189
PyAPI_FUNC(PyObject *) _PySys_Init(void);
190190
PyAPI_FUNC(void) _PyImport_Init(void);
191-
PyAPI_FUNC(void) _PyExc_Init(void);
191+
PyAPI_FUNC(void) _PyExc_Init(PyObject * bltinmod);
192192
PyAPI_FUNC(void) _PyImportHooks_Init(void);
193193
PyAPI_FUNC(int) _PyFrame_Init(void);
194194
PyAPI_FUNC(void) _PyFloat_Init(void);

Lib/importlib/_bootstrap.py

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,13 @@ def _wrap(new, old):
160160

161161
# Finder/loader utility code ##################################################
162162

163+
def verbose_message(message, *args):
164+
"""Print the message to stderr if -v/PYTHONVERBOSE is turned on."""
165+
if sys.flags.verbose:
166+
if not message.startswith('#') and not message.startswith('import '):
167+
message = '# ' + message
168+
print(message.format(*args), file=sys.stderr)
169+
163170

164171
def set_package(fxn):
165172
"""Set __package__ on the returned module."""
@@ -388,19 +395,24 @@ def _bytes_from_bytecode(self, fullname, data, bytecode_path, source_stats):
388395
raise ImportError("bad magic number in {}".format(fullname),
389396
name=fullname, path=bytecode_path)
390397
elif len(raw_timestamp) != 4:
391-
raise EOFError("bad timestamp in {}".format(fullname))
398+
message = 'bad timestamp in {}'.format(fullname)
399+
verbose_message(message)
400+
raise EOFError(message)
392401
elif len(raw_size) != 4:
393-
raise EOFError("bad size in {}".format(fullname))
402+
message = 'bad size in {}'.format(fullname)
403+
verbose_message(message)
404+
raise EOFError(message)
394405
if source_stats is not None:
395406
try:
396407
source_mtime = int(source_stats['mtime'])
397408
except KeyError:
398409
pass
399410
else:
400411
if _r_long(raw_timestamp) != source_mtime:
401-
raise ImportError(
402-
"bytecode is stale for {}".format(fullname),
403-
name=fullname, path=bytecode_path)
412+
message = 'bytecode is stale for {}'.format(fullname)
413+
verbose_message(message)
414+
raise ImportError(message, name=fullname,
415+
path=bytecode_path)
404416
try:
405417
source_size = source_stats['size'] & 0xFFFFFFFF
406418
except KeyError:
@@ -506,9 +518,13 @@ def get_code(self, fullname):
506518
except (ImportError, EOFError):
507519
pass
508520
else:
521+
verbose_message('{} matches {}', bytecode_path,
522+
source_path)
509523
found = marshal.loads(bytes_data)
510524
if isinstance(found, code_type):
511525
imp._fix_co_filename(found, source_path)
526+
verbose_message('code object from {}',
527+
bytecode_path)
512528
return found
513529
else:
514530
msg = "Non-code object in {}"
@@ -517,6 +533,7 @@ def get_code(self, fullname):
517533
source_bytes = self.get_data(source_path)
518534
code_object = compile(source_bytes, source_path, 'exec',
519535
dont_inherit=True)
536+
verbose_message('code object from {}', source_path)
520537
if (not sys.dont_write_bytecode and bytecode_path is not None and
521538
source_mtime is not None):
522539
# If e.g. Jython ever implements imp.cache_from_source to have
@@ -528,6 +545,7 @@ def get_code(self, fullname):
528545
data.extend(marshal.dumps(code_object))
529546
try:
530547
self.set_data(bytecode_path, data)
548+
verbose_message('wrote {!r}', bytecode_path)
531549
except NotImplementedError:
532550
pass
533551
return code_object
@@ -596,6 +614,7 @@ def set_data(self, path, data):
596614
return
597615
try:
598616
_write_atomic(path, data)
617+
verbose_message('created {!r}', path)
599618
except (PermissionError, FileExistsError):
600619
# Don't worry if you can't write bytecode or someone is writing
601620
# it at the same time.
@@ -615,6 +634,7 @@ def get_code(self, fullname):
615634
bytes_data = self._bytes_from_bytecode(fullname, data, path, None)
616635
found = marshal.loads(bytes_data)
617636
if isinstance(found, code_type):
637+
verbose_message('code object from {!r}', path)
618638
return found
619639
else:
620640
raise ImportError("Non-code object in {}".format(path),
@@ -644,7 +664,9 @@ def load_module(self, fullname):
644664
"""Load an extension module."""
645665
is_reload = fullname in sys.modules
646666
try:
647-
return imp.load_dynamic(fullname, self._path)
667+
module = imp.load_dynamic(fullname, self._path)
668+
verbose_message('extension module loaded from {!r}', self._path)
669+
return module
648670
except:
649671
if not is_reload and fullname in sys.modules:
650672
del sys.modules[fullname]
@@ -953,6 +975,7 @@ def _find_and_load(name, import_):
953975
elif name not in sys.modules:
954976
# The parent import may have already imported this module.
955977
loader.load_module(name)
978+
verbose_message('import {!r} # {!r}', name, loader)
956979
# Backwards-compatibility; be nicer to skip the dict lookup.
957980
module = sys.modules[name]
958981
if parent:

Lib/importlib/test/import_/test_path.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ def test_path_importer_cache_empty_string(self):
8787

8888
class DefaultPathFinderTests(unittest.TestCase):
8989

90-
"""Test importlib._bootstrap._DefaultPathFinder."""
90+
"""Test _bootstrap._DefaultPathFinder."""
9191

9292
def test_implicit_hooks(self):
9393
# Test that the implicit path hooks are used.

Lib/importlib/test/import_/util.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import functools
22
import importlib
3-
import importlib._bootstrap
43
import unittest
54

65

Lib/importlib/test/regrtest.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,4 @@
1313
if __name__ == '__main__':
1414
__builtins__.__import__ = importlib.__import__
1515

16-
exclude = ['--exclude',
17-
'test_frozen', # Does not expect __loader__ attribute
18-
'test_pkg', # Does not expect __loader__ attribute
19-
'test_pydoc', # Does not expect __loader__ attribute
20-
]
21-
22-
# Switching on --exclude implies running all test but the ones listed, so
23-
# only use it when one is not running an explicit test
24-
if len(sys.argv) == 1:
25-
# No programmatic way to specify tests to exclude
26-
sys.argv.extend(exclude)
27-
2816
regrtest.main(quiet=True, verbose2=True)

Lib/importlib/test/source/test_file_loader.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
from ... import _bootstrap
12
import importlib
2-
from importlib import _bootstrap
33
from .. import abc
44
from .. import util
55
from . import util as source_util

0 commit comments

Comments
 (0)