[3.12] gh-123085: Fix issue in inferred caller when resources package has no source (GH-123102) (#124021)

gh-123085: Fix issue in inferred caller when resources package has no source.

From importlib_resources 6.4.3 (python/importlib_resourcesGH-314).
(cherry picked from commit a53812df12)
This commit is contained in:
Jason R. Coombs 2025-01-05 16:53:55 -05:00 committed by GitHub
parent 09f7d88cad
commit d712ece43f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 50 additions and 4 deletions

View file

@ -93,12 +93,13 @@ def _infer_caller():
""" """
def is_this_file(frame_info): def is_this_file(frame_info):
return frame_info.filename == __file__ return frame_info.filename == stack[0].filename
def is_wrapper(frame_info): def is_wrapper(frame_info):
return frame_info.function == 'wrapper' return frame_info.function == 'wrapper'
not_this_file = itertools.filterfalse(is_this_file, inspect.stack()) stack = inspect.stack()
not_this_file = itertools.filterfalse(is_this_file, stack)
# also exclude 'wrapper' due to singledispatch in the call stack # also exclude 'wrapper' due to singledispatch in the call stack
callers = itertools.filterfalse(is_wrapper, not_this_file) callers = itertools.filterfalse(is_wrapper, not_this_file)
return next(callers).frame return next(callers).frame

View file

@ -1,4 +1,8 @@
import typing import typing
import os
import pathlib
import py_compile
import shutil
import textwrap import textwrap
import unittest import unittest
import warnings import warnings
@ -10,8 +14,7 @@ from importlib.resources.abc import Traversable
from . import data01 from . import data01
from . import util from . import util
from . import _path from . import _path
from test.support import os_helper from test.support import os_helper, import_helper
from test.support import import_helper
@contextlib.contextmanager @contextlib.contextmanager
@ -144,6 +147,45 @@ class ImplicitContextFilesTests(SiteDir, unittest.TestCase):
self.fixtures.enter_context(import_helper.DirsOnSysPath(zip_file)) self.fixtures.enter_context(import_helper.DirsOnSysPath(zip_file))
assert importlib.import_module('somepkg.submod').val == 'resources are the best' assert importlib.import_module('somepkg.submod').val == 'resources are the best'
def _compile_importlib(self):
"""
Make a compiled-only copy of the importlib resources package.
"""
bin_site = self.fixtures.enter_context(os_helper.temp_dir())
c_resources = pathlib.Path(bin_site, 'c_resources')
sources = pathlib.Path(resources.__file__).parent
shutil.copytree(sources, c_resources, ignore=lambda *_: ['__pycache__'])
for dirpath, _, filenames in os.walk(c_resources):
for filename in filenames:
source_path = pathlib.Path(dirpath) / filename
cfile = source_path.with_suffix('.pyc')
py_compile.compile(source_path, cfile)
pathlib.Path.unlink(source_path)
self.fixtures.enter_context(import_helper.DirsOnSysPath(bin_site))
def test_implicit_files_with_compiled_importlib(self):
"""
Caller detection works for compiled-only resources module.
python/cpython#123085
"""
set_val = textwrap.dedent(
f"""
import {resources.__name__} as res
val = res.files().joinpath('res.txt').read_text(encoding='utf-8')
"""
)
spec = {
'frozenpkg': {
'__init__.py': set_val.replace(resources.__name__, 'c_resources'),
'res.txt': 'resources are the best',
},
}
_path.build(spec, self.site_dir)
self._compile_importlib()
assert importlib.import_module('frozenpkg').val == 'resources are the best'
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View file

@ -0,0 +1,3 @@
In a bare call to :func:`importlib.resources.files`, ensure the caller's
frame is properly detected when ``importlib.resources`` is itself available
as a compiled module only (no source).