diff options
author | Eric Snow <ericsnowcurrently@gmail.com> | 2021-10-05 16:01:27 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-05 16:01:27 (GMT) |
commit | c3d9ac8b340fcbf54cee865737e67f11fcd70ed3 (patch) | |
tree | 71171709f9a44e02cca8ffee4a0fe2c49335b59a /Lib/importlib | |
parent | b9bb74871b27d9226df2dd3fce9d42bda8b43c2b (diff) | |
download | cpython-c3d9ac8b340fcbf54cee865737e67f11fcd70ed3.zip cpython-c3d9ac8b340fcbf54cee865737e67f11fcd70ed3.tar.gz cpython-c3d9ac8b340fcbf54cee865737e67f11fcd70ed3.tar.bz2 |
bpo-45324: Capture data in FrozenImporter.find_spec() to use in exec_module(). (gh-28633)
Before this change we end up duplicating effort and throwing away data in FrozenImporter.find_spec(). Now we do the work once in find_spec() and the only thing we do in FrozenImporter.exec_module() is turn the raw frozen data into a code object and then exec it.
We've added _imp.find_frozen(), add an arg to _imp.get_frozen_object(), and updated FrozenImporter. We've also moved some code around to reduce duplication, get a little more consistency in outcomes, and be more efficient.
Note that this change is mostly necessary if we want to set __file__ on frozen stdlib modules. (See https://bugs.python.org/issue21736.)
https://bugs.python.org/issue45324
Diffstat (limited to 'Lib/importlib')
-rw-r--r-- | Lib/importlib/_bootstrap.py | 32 |
1 files changed, 24 insertions, 8 deletions
diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index e64f7ad..5807577 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -826,10 +826,15 @@ class FrozenImporter: @classmethod def find_spec(cls, fullname, path=None, target=None): - if _imp.is_frozen(fullname): - return spec_from_loader(fullname, cls, origin=cls._ORIGIN) - else: + info = _call_with_frames_removed(_imp.find_frozen, fullname) + if info is None: return None + data, ispkg = info + spec = spec_from_loader(fullname, cls, + origin=cls._ORIGIN, + is_package=ispkg) + spec.loader_state = data + return spec @classmethod def find_module(cls, fullname, path=None): @@ -849,11 +854,22 @@ class FrozenImporter: @staticmethod def exec_module(module): - name = module.__spec__.name - if not _imp.is_frozen(name): - raise ImportError('{!r} is not a frozen module'.format(name), - name=name) - code = _call_with_frames_removed(_imp.get_frozen_object, name) + spec = module.__spec__ + name = spec.name + try: + data = spec.loader_state + except AttributeError: + if not _imp.is_frozen(name): + raise ImportError('{!r} is not a frozen module'.format(name), + name=name) + data = None + else: + # We clear the extra data we got from the finder, to save memory. + # Note that if this method is called again (e.g. by + # importlib.reload()) then _imp.get_frozen_object() will notice + # no data was provided and will look it up. + spec.loader_state = None + code = _call_with_frames_removed(_imp.get_frozen_object, name, data) exec(code, module.__dict__) @classmethod |