A potential bug in get_class_in_module by using subprocess to copy files among temp dir.
Author: maofagui
Pull request: no

### System Info

- `transformers` version: 4.28.0.dev0
- Platform: macOS-10.15.7-x86_64-i386-64bit
- Python version: 3.8.16
- Huggingface_hub version: 0.13.3
- Safetensors version: not installed
- PyTorch version (GPU?): 1.13.1 (False)
- Tensorflow version (GPU?): not installed (NA)
- Flax version (CPU?/GPU?/TPU?): not installed (NA)
- Jax version: not installed
- JaxLib version: not installed
- Using GPU in script?: no need
- Using distributed or parallel set-up in script?: no need


### Who can help?

@ydshieh @sgugger 

### Information

- [ ] The official example scripts
- [X] My own modified scripts

### Tasks

- [ ] An officially supported task in the `examples` folder (such as GLUE/SQuAD, ...)
- [X] My own task or dataset (give details below)

### Reproduction

The function in `dynamic_module_utils.py` as below will cause a `No such file or directory` error in parallel env (namely multiple process).
```
def get_class_in_module(class_name, module_path):
    """
    Import a module on the cache directory for modules and extract a class from it.
    """
    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}")'
        # We don't know which python binary file exists in an environment. For example, if `python3` exists but not
        # `python`, the call `subprocess.run(["python", ...])` gives `FileNotFoundError` (about python binary). Notice
        # that, if the file to be removed is not found, we also have `FileNotFoundError`, but it is not raised to the
        # caller's process.
        try:
            subprocess.run(["python", "-c", cmd])
        except FileNotFoundError:
            try:
                subprocess.run(["python3", "-c", cmd])
            except FileNotFoundError:
                pass

        # 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)
```
The below error can be reproduced by the same code fragment in [issue22555](https://github.com/huggingface/transformers/issues/22555). 

```
Process p4:
/var/folders/pv/nyl4rqb54tq1bslm06h34m840000gp/T/tmpebghdmvd/configuration_glm.py
Traceback (most recent call last):
  File "/opt/miniconda3/envs/py38_torch/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
    self.run()
  File "/opt/miniconda3/envs/py38_torch/lib/python3.8/multiprocessing/process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
  File "/Users/mfg/Code/torch_submit/mp_load_model/main.py", line 9, in func
    model = AutoModel.from_pretrained(local_dir, trust_remote_code=True)
  File "/Users/mfg/Code/transformers/src/transformers/models/auto/auto_factory.py", line 441, in from_pretrained
    config, kwargs = AutoConfig.from_pretrained(
  File "/Users/mfg/Code/transformers/src/transformers/models/auto/configuration_auto.py", line 923, in from_pretrained
    config_class = get_class_from_dynamic_module(
  File "/Users/mfg/Code/transformers/src/transformers/dynamic_module_utils.py", line 400, in get_class_from_dynamic_module
    return get_class_in_module(class_name, final_module.replace(".py", ""))
  File "/Users/mfg/Code/transformers/src/transformers/dynamic_module_utils.py", line 178, in get_class_in_module
    module = importlib.import_module(module_path)
  File "/opt/miniconda3/envs/py38_torch/lib/python3.8/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 839, in exec_module
  File "<frozen importlib._bootstrap_external>", line 975, in get_code
  File "<frozen importlib._bootstrap_external>", line 1032, in get_data
FileNotFoundError: [Errno 2] No such file or directory: '/Users/mfg/.cache/huggingface/modules/transformers_modules/glm-10b/configuration_glm.py'

```

This error only occurs in single machine for the reason of race condition on a same file or dir. 
So I think it is a good way to solve it by using FileLock as below:

```
import fcntl
import os

class FileLock(object):
    def __init__(self, file_path):
        self.file_path = file_path
        self.fd = None

    def __enter__(self):
        while True:
            try:
                self.fd = os.open(self.file_path, os.O_RDWR | os.O_CREAT)
                fcntl.lockf(self.fd, fcntl.LOCK_EX)
                return
            except:
                pass

    def __exit__(self, exc_type, exc_val, exc_tb):
        fcntl.lockf(self.fd, fcntl.LOCK_UN)
        os.close(self.fd)
```

Usage:

```
def get_class_in_module(class_name, module_path):
    """
    Import a module on the cache directory for modules and extract a class from it.
    """
    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"

        lock_file = f"./transformers/{module_file_name}_lockfile"
        lock = FileLock(lock_file)
        with lock:
            # 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)
            ...
```
I have test this solution in my local machine and meet no error any more.
Any comments are welcome~



### Expected behavior

Can work in multiple process.

Comments:
This has been fixed by #22537 

This issue has been automatically marked as stale because it has not had recent activity. If you think this still needs to be addressed please comment on this thread.

Please note that issues that do not follow the [contributing guidelines](https://github.com/huggingface/transformers/blob/main/CONTRIBUTING.md) are likely to be ignored.