python / python/cpython

linecache cannot read the source of modules imported from a .zip when given only the file name

Open
#157,146 1 comment 0 reactions 1 assignee View on GitHub

@gpshead is already working on this.

Since Sep 8, 2026.

stdlib type-bug
Dominant language
Python
Stars
77.2k
Forks
35.9k
PR merge metrics
PR metrics pending

Description

Bug report

Bug description:

linecache.getlines(filename) and .getline(filename, lineno) return nothing for a module that was imported from a zip archive on sys.path via zipimport, unless the caller also passes module_globals.

For such modules, __file__ and .co_filename look like /path/to/archive.zip/pkg/mod.py. In linecache.updatecache(), the os.stat() on that path fails (NotADirectoryError), the lazy-loader lookup only works when module_globals is supplied, and the final fallback that searches sys.path only handles relative file names. So the lookup gives up and returns [].

Many callers only have the file name: pdb's list command, warnings (when the module globals are gone), doctest, inspect.getsourcefile() fallbacks, and traceback formatting of code objects whose frames have been cleared. For a file on disk these all work; for the same module inside a zip they silently show no source.

import linecache, sys, zipfile
with zipfile.ZipFile('mods.zip', 'w') as zf:
    zf.writestr('zipmod.py', 'def f():\n    return 1\n')
sys.path.insert(0, 'mods.zip')
import zipmod
print(linecache.getlines(zipmod.__file__))   # [] but should be the two source lines
print(linecache.getline(zipmod.f.__code__.co_filename,
                        zipmod.f.__code__.co_firstlineno))  # '' but should be 'def f():\n'

The information needed is already available: zipimport.zipimporter implements get_data(pathname), which accepts exactly these absolute paths, and sys.path_importer_cache maps the archive path to that importer.

Proposed fix: after the lazy-loader attempt fails, have updatecache() check whether the file name lies under a sys.path_importer_cache entry whose finder has get_data()...

This also benefits any other path entry finder that provides get_data() for an archive.

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs
  • gh-157147
  • gh-157269

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.