Skip to content

Commit 485c71d

Browse files
committed
Walk transformers package via importlib.resources at lazy-import time
1 parent 7bc093b commit 485c71d

1 file changed

Lines changed: 42 additions & 18 deletions

File tree

src/transformers/utils/import_utils.py

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
import functools
1919
import importlib.machinery
2020
import importlib.metadata
21+
import importlib.resources
2122
import importlib.util
2223
import json
2324
import operator
2425
import os
26+
import pathlib
2527
import re
2628
import shutil
2729
import subprocess
@@ -2671,6 +2673,25 @@ def fetch__all__(file_content) -> list[str]:
26712673
return _all
26722674

26732675

2676+
def _resolve_traversable(module_path):
2677+
"""Return a Traversable for `module_path`."""
2678+
transformers_module = sys.modules.get("transformers")
2679+
if transformers_module is not None and getattr(transformers_module, "__file__", None) is not None:
2680+
pkg_root = pathlib.Path(transformers_module.__file__).parent
2681+
try:
2682+
rel = pathlib.PurePath(module_path).relative_to(pkg_root)
2683+
except ValueError:
2684+
pass
2685+
else:
2686+
traversable = importlib.resources.files("transformers")
2687+
for part in rel.parts:
2688+
traversable = traversable.joinpath(part)
2689+
return traversable
2690+
2691+
# Fall back to pathlib.Path for paths outside the transformers package.
2692+
return pathlib.Path(module_path)
2693+
2694+
26742695
@lru_cache
26752696
def create_import_structure_from_path(module_path):
26762697
"""
@@ -2724,36 +2745,39 @@ def create_import_structure_from_path(module_path):
27242745
}
27252746
}
27262747
"""
2727-
import_structure = {}
2728-
2729-
if os.path.isfile(module_path):
2748+
module_path = str(module_path)
2749+
if module_path.endswith(".py"):
27302750
module_path = os.path.dirname(module_path)
2751+
return _create_import_structure_from_traversable(_resolve_traversable(module_path))
27312752

2732-
adjacent_modules = []
27332753

2734-
with os.scandir(module_path) as entries:
2735-
for entry in entries:
2736-
if entry.name == "__pycache__":
2737-
continue
2738-
if entry.is_dir():
2739-
import_structure[entry.name] = create_import_structure_from_path(entry.path)
2740-
elif not entry.name.startswith(("convert_", "modular_")):
2741-
adjacent_modules.append(entry.name)
2754+
def _create_import_structure_from_traversable(traversable):
2755+
"""Walk a Traversable and build the import structure."""
2756+
import_structure = {}
2757+
adjacent_entries = []
2758+
2759+
for entry in traversable.iterdir():
2760+
if entry.name == "__pycache__":
2761+
continue
2762+
if entry.is_dir():
2763+
# Recurse via the Traversable, not `files(subpackage)` — the latter would force-import the subpackage.
2764+
import_structure[entry.name] = _create_import_structure_from_traversable(entry)
2765+
elif not entry.name.startswith(("convert_", "modular_")):
2766+
adjacent_entries.append(entry)
27422767

27432768
# We're only taking a look at files different from __init__.py
27442769
# We could theoretically require things directly from the __init__.py
27452770
# files, but this is not supported at this time.
2746-
if "__init__.py" in adjacent_modules:
2747-
adjacent_modules.remove("__init__.py")
2771+
adjacent_entries = [e for e in adjacent_entries if e.name != "__init__.py"]
27482772

27492773
module_requirements = {}
2750-
for module_name in adjacent_modules:
2774+
for entry in adjacent_entries:
27512775
# Only modules ending in `.py` are accepted here.
2752-
if not module_name.endswith(".py"):
2776+
if not entry.name.endswith(".py"):
27532777
continue
27542778

2755-
with open(os.path.join(module_path, module_name), encoding="utf-8") as f:
2756-
file_content = f.read()
2779+
module_name = entry.name
2780+
file_content = entry.read_text(encoding="utf-8")
27572781

27582782
# Remove the .py suffix
27592783
module_name = module_name[:-3]

0 commit comments

Comments
 (0)