-
Notifications
You must be signed in to change notification settings - Fork 27.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix dynamic module import error #21646
Changes from all commits
6d83254
2472668
37a046c
ab57566
da2e785
93c973d
7bf2582
e347d17
c4cadb7
d13ed84
f5c1d12
f10b2d8
cbf45dc
b9c583e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,9 @@ | |
import os | ||
import re | ||
import shutil | ||
import subprocess | ||
import sys | ||
import tempfile | ||
from pathlib import Path | ||
from typing import Dict, Optional, Union | ||
|
||
|
@@ -143,9 +145,25 @@ def get_class_in_module(class_name, module_path): | |
""" | ||
Import a module on the cache directory for modules and extract a class from it. | ||
""" | ||
module_path = module_path.replace(os.path.sep, ".") | ||
module = importlib.import_module(module_path) | ||
return getattr(module, class_name) | ||
with tempfile.TemporaryDirectory() as tmp_dir: | ||
module_dir = Path(HF_MODULES_CACHE) / os.path.dirname(module_path) | ||
module_file_name = module_path.split(os.path.sep)[-1] + ".py" | ||
|
||
# Copy to a temporary directory. We need to do this in another process to avoid strange and flaky error | ||
# `ModuleNotFoundError: No module named 'transformers_modules.[module_dir_name].modeling'` | ||
shutil.copy(f"{module_dir}/{module_file_name}", tmp_dir) | ||
# On Windows, we need this character `r` before the path argument of `os.remove` | ||
cmd = f'import os; os.remove(r"{module_dir}{os.path.sep}{module_file_name}")' | ||
subprocess.run(["python", "-c", cmd]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If something goes wrong in the
Let me know if you have any suggestion :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need to do something? If there is a problem deleting the file (which we copy just after), at worst we get the flaky failure again (though it should be extremely rare at this stage). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, right! |
||
|
||
# copy back the file that we want to import | ||
shutil.copyfile(f"{tmp_dir}/{module_file_name}", f"{module_dir}/{module_file_name}") | ||
|
||
# import the module | ||
module_path = module_path.replace(os.path.sep, ".") | ||
module = importlib.import_module(module_path) | ||
|
||
return getattr(module, class_name) | ||
|
||
|
||
def get_cached_module_file( | ||
|
@@ -212,7 +230,7 @@ def get_cached_module_file( | |
# Download and cache module_file from the repo `pretrained_model_name_or_path` of grab it if it's a local file. | ||
pretrained_model_name_or_path = str(pretrained_model_name_or_path) | ||
if os.path.isdir(pretrained_model_name_or_path): | ||
submodule = "local" | ||
submodule = pretrained_model_name_or_path.split(os.path.sep)[-1] | ||
else: | ||
submodule = pretrained_model_name_or_path.replace("/", os.path.sep) | ||
|
||
|
@@ -240,7 +258,7 @@ def get_cached_module_file( | |
full_submodule = TRANSFORMERS_DYNAMIC_MODULE_NAME + os.path.sep + submodule | ||
create_dynamic_module(full_submodule) | ||
submodule_path = Path(HF_MODULES_CACHE) / full_submodule | ||
if submodule == "local": | ||
if submodule == pretrained_model_name_or_path.split(os.path.sep)[-1]: | ||
# We always copy local files (we could hash the file to see if there was a change, and give them the name of | ||
# that hash, to only copy when there is a modification but it seems overkill for now). | ||
# The only reason we do the copy is to avoid putting too many folders in sys.path. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not the location to load the module. It's just to hold the file temporarily , and it will be copied back to the original place.