.. index:: triple: module; search; path
+ If *filename* indicates a frozen module (starting with ``'<frozen '``), the function
+ will attepmt to get the real file name from ``module_globals['__file__']`` if
+ *module_globals* is not ``None``.
+
If a file named *filename* is not found, the function first checks
for a :pep:`302` ``__loader__`` in *module_globals*.
If there is such a loader and it defines a ``get_source`` method,
Finally, if *filename* is a relative filename,
it is looked up relative to the entries in the module search path, ``sys.path``.
+ .. versionchanged:: 3.14
+
+ Support *filename* of frozen modules.
+
.. function:: clearcache()
(Contributed by Trey Hunner in :gh:`122873`.)
+linecache
+---------
+
+* :func:`linecache.getline` can retrieve source code for frozen modules.
+ (Contributed by Tian Gao in :gh:`131638`.)
+
+
mimetypes
---------
return []
+def _source_unavailable(filename):
+ """Return True if the source code is unavailable for such file name."""
+ return (
+ not filename
+ or (filename.startswith('<')
+ and filename.endswith('>')
+ and not filename.startswith('<frozen '))
+ )
+
+
def checkcache(filename=None):
"""Discard cache entries that are out of date.
(This is not checked upon each call!)"""
if filename in cache:
if len(cache[filename]) != 1:
cache.pop(filename, None)
- if not filename or (filename.startswith('<') and filename.endswith('>')):
+ if _source_unavailable(filename):
return []
- fullname = filename
+ if filename.startswith('<frozen ') and module_globals is not None:
+ # This is a frozen module, so we need to use the filename
+ # from the module globals.
+ fullname = module_globals.get('__file__')
+ if fullname is None:
+ return []
+ else:
+ fullname = filename
try:
stat = os.stat(fullname)
except OSError:
self.assertEqual(linecache.getlines(filename, module_globals),
['source for x.y.z\n'])
+ def test_frozen(self):
+ filename = '<frozen fakemodule>'
+ module_globals = {'__file__': FILENAME}
+ empty = linecache.getlines(filename)
+ self.assertEqual(empty, [])
+ lines = linecache.getlines(filename, module_globals)
+ self.assertGreater(len(lines), 0)
+ lines_cached = linecache.getlines(filename)
+ self.assertEqual(lines, lines_cached)
+ linecache.clearcache()
+ empty = linecache.getlines(filename)
+ self.assertEqual(empty, [])
+
def test_invalid_names(self):
for name, desc in [
('\x00', 'NUL bytes filename'),
--- /dev/null
+Support frozen modules for :func:`linecache.getline`.