python / python/cpython

importlib.resources.files() doesn't work correctly when importlib library is compiled

Offen
#123,085 6 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

stdlib topic-importlib type-bug
Vorherrschende Sprache
Python
Sterne
77.2k
Forks
36k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

Bug report

Bug description:

If importlib library is compiled (in particular _common.py), then any package, that uses bare files() to get its resources, breaks, because _infer_caller returns wrong frame (as mentioned in https://github.com/python/cpython/pull/123037#issuecomment-2294431430, __file__ in https://github.com/python/cpython/blob/35d8ac7cd7ed6cd3d84af721dce970da59bd5f68/Lib/importlib/resources/_common.py#L96 is not valid)

Reproducer:

import importlib
import os
import pathlib
import py_compile
import shutil
import sys
import tempfile
import textwrap


def compile(tempdir):
    target_dir = pathlib.Path(tempdir) / 'cimportlib'
    souce_dir = pathlib.Path(importlib.__file__).parent
    shutil.copytree(souce_dir, target_dir, ignore=lambda *_: ['__pycache__'])

    for dirpath, _, filenames in os.walk(target_dir):
        for filename in filenames:
            if filename != "_common.py":
                continue
            source_path = pathlib.Path(dirpath) / filename
            cfile = source_path.with_suffix('.pyc')
            py_compile.compile(source_path, cfile)
            pathlib.Path.unlink(source_path)


def create_package(tempdir):
    package_dir = pathlib.Path(tempdir) / 'somepkg'
    package_dir.mkdir()
    contents = {
        "__init__.py": textwrap.dedent(
            """
            import cimportlib.resources as res
            val = res.files().joinpath('resource.txt').read_text(encoding='utf-8')
            """
        ),
        "resource.txt": "data",
    }

    for file, content in contents.items():
        path = pathlib.Path(package_dir) / file
        path.write_text(content)


def main():
    with tempfile.TemporaryDirectory() as tempdir:
        compile(tempdir)
        create_package(tempdir)
        sys.path.insert(0, str(tempdir))
        print(importlib.import_module('somepkg').val)


if __name__ == "__main__":
    raise SystemExit(main())

Expectation:

data

Actual outcome:

FileNotFoundError: [Errno 2] No such file or directory: '/tmp/tmpngnuw441/cimportlib/resources/resource.txt'

It may be important for frozen python applications, as they don't include source code

CPython versions tested on:

3.12, CPython main branch

Operating systems tested on:

Linux, Windows

Linked PRs
  • gh-123102
  • gh-124021
  • gh-124024
  • gh-124131
  • gh-128581
  • gh-128600
  • gh-137914

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginnen Sie mit Lib/importlib/resources/_common.py, insbesondere mit _infer_caller und der referenzierten Zeile, und reproduzieren Sie anschließend den Fehler mit dem bereitgestellten Skript unter Verwendung einer kompilierten _common.py. Vergleichen Sie die erwartete Datenausgabe mit dem FileNotFoundError; als erledigt gilt die Aufgabe, wenn der Reproducer mit kompiliertem importlib funktioniert, ohne das normale Laden von Ressourcen zu beeinträchtigen.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
backend
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
25/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.