Repository: huggingface/transformers

Issue:
transformers.__spec__ returning None. Causing downstream import errors
## Environment info
<!-- You can run the command `transformers-cli env` and copy-and-paste its output below.
     Don't forget to fill out the missing fields in that output! -->

- `transformers` version: Tried on 4.6.1(current default kaggle version)/4.8.1/4.8.2 and 4.9.1
- Platform: Colab/Kaggle/ My Local Runtime
- Python version: 3.7.11

### Who can help
<!-- Your issue will be replied to more quickly if you can figure out the right person to tag with @
 If you know how to use git blame, that is the easiest way, otherwise, here is a rough guide of **who to tag**.
 Please tag fewer than 3 people.

Models:

- albert, bert, xlm: @LysandreJik
- blenderbot, bart, marian, pegasus, encoderdecoder,  t5: @patrickvonplaten, @patil-suraj
- longformer, reformer, transfoxl, xlnet: @patrickvonplaten
- fsmt: @stas00
- funnel: @sgugger
- gpt2: @patrickvonplaten, @LysandreJik
- rag: @patrickvonplaten, @lhoestq
- tensorflow: @Rocketknight1

Library:

- benchmarks: @patrickvonplaten
- deepspeed: @stas00
- ray/raytune: @richardliaw, @amogkam
- text generation: @patrickvonplaten
- tokenizers: @LysandreJik
- trainer: @sgugger
- pipelines: @LysandreJik

Documentation: @sgugger

Model hub:

- for issues with a model report at https://discuss.huggingface.co/ and tag the model's creator.

HF projects:

- datasets: [different repo](https://github.com/huggingface/datasets)
- rust tokenizers: [different repo](https://github.com/huggingface/tokenizers)

Examples:

- maintained examples (not research project or legacy): @sgugger, @patil-suraj
- research_projects/bert-loses-patience: @JetRunner
- research_projects/distillation: @VictorSanh

 -->

## Information

This is causing downstream import errors, like right now I am not able to import [`lightning-flash`](https://github.com/PyTorchLightning/lightning-flash) properly as it uses `__spec__` in order to find the availability of `transformers`.
```
ValueError                                Traceback (most recent call last)
<ipython-input-3-76e523923a79> in <module>
      5 print(transformers.__version__)
      6 print(transformers.__spec__)
----> 7 from flash import Trainer
      8 #from flash.core.data.utils import download_data
      9 #from flash.text import SummarizationData, SummarizationTask

/opt/conda/lib/python3.7/site-packages/flash/__init__.py in <module>
     16 
     17 from flash.__about__ import *  # noqa: F401 F403
---> 18 from flash.core.utilities.imports import _TORCH_AVAILABLE
     19 
     20 if _TORCH_AVAILABLE:

/opt/conda/lib/python3.7/site-packages/flash/core/utilities/imports.py in <module>
     75 _PYTORCHVIDEO_AVAILABLE = _module_available("pytorchvideo")
     76 _MATPLOTLIB_AVAILABLE = _module_available("matplotlib")
---> 77 _TRANSFORMERS_AVAILABLE = _module_available("transformers")
     78 _PYSTICHE_AVAILABLE = _module_available("pystiche")
     79 _FIFTYONE_AVAILABLE = _module_available("fiftyone")

/opt/conda/lib/python3.7/site-packages/flash/core/utilities/imports.py in _module_available(module_path)
     36     """
     37     try:
---> 38         return find_spec(module_path) is not None
     39     except AttributeError:
     40         # Python 3.6

/opt/conda/lib/python3.7/importlib/util.py in find_spec(name, package)
    112         else:
    113             if spec is None:
--> 114                 raise ValueError('{}.__spec__ is None'.format(name))
    115             return spec
    116 

ValueError: transformers.__spec__ is None
```
## To reproduce

<!-- If you have code snippets, error messages, stack traces please provide them here as well.
     Important! Use code tags to correctly format your code. See https://help.github.com/en/github/writing-on-github/creating-and-highlighting-code-blocks#syntax-highlighting
     Do not use screenshots, as they are hard to read and (more importantly) don't allow others to copy-and-paste your code.-->

```

import transformers
print(transformers.__version__)
print(transformers.__spec__)

4.9.1
None

```

## Expected behavior

Properly defined `__spec__`
<!-- A clear and concise description of what you would expect to happen. -->



Discussion:
`__spec__` is used by the Python import system internally, I am not reading anywhere that it should be defined manually by the package creators. If you have more resources about this I'm happy to look into what we could add, but a quick Google search yields nothing.
> `__spec__` is used by the Python import system internally, I am not reading anywhere that it should be defined manually by the package creators. If you have more resources about this I'm happy to look into what we could add, but a quick Google search yields nothing.

My bad, at the time of error I found this issue on tensorflow/tensorflow#30028, and thought it was the same. After reading [this](https://docs.python.org/3/reference/import.html#module-spec), I somewhat understood the the functionality of `__spec__`.:thumbsup:
@sgugger I'm also getting the same error with the latest transformers version (4.9.2) when I'm trying to use torch.hub to load a model that has `transformers` as a dependency. It seems that torch.hub tries to check if dependencies exist by verifying that  `transformers.__spec__` is not None (source code [here](https://github.com/pytorch/pytorch/blob/b0396e39f41da9f61c61ed8758b5e9505a370ebc/torch/hub.py#L198)) resulting in an error otherwise. 

Before I was using an older version of transformers (3.9.2) that returned a `ModuleSpec` object for `transformers.__spec__` so loading the same model with torch.hub worked, just wondering why this has changed and whether it should be defined?
After investigating this further, it does seem particular to the `transformers` library that `__spec__` returns `None` after importing it (other libraries still return something without having it explicitly defined). 

Although it does seem that normally python's import system handles `__spec__` internally and it does not need to be defined manually, it should return something automatically and not doing so could cause downstream problems e.g. when checking that dependencies exist:

> Looks like the difference lies in whether `transformers` is manually imported or not:
> 
> ```python
> In [1]: import importlib
> 
> In [2]: importlib.util.find_spec("transformers") is not None
> Out[2]: True
> 
> In [3]: import transformers
> 
> In [4]: importlib.util.find_spec("transformers") is not None
> ---------------------------------------------------------------------------
> ValueError                                Traceback (most recent call last)
> <ipython-input-4-6fdb35471f82> in <module>
> ----> 1 importlib.util.find_spec("transformers") is not None
> 
> ~/opt/miniconda3/envs/pt/lib/python3.8/importlib/util.py in find_spec(name, package)
>     112         else:
>     113             if spec is None:
> --> 114                 raise ValueError('{}.__spec__ is None'.format(name))
>     115             return spec
>     116
> 
> ValueError: transformers.__spec__ is None
> ```
> 
> This looks like something specific to the `transformers` package though, it doesn't happen e.g. with numpy:
> 
> ```python
> In [5]: importlib.util.find_spec("numpy") is not None
> Out[5]: True
> 
> In [6]: import numpy
> 
> In [7]: importlib.util.find_spec("numpy") is not None
> Out[7]: True
> ```
> 




Resolving patch:
diff --git a/src/transformers/__init__.py b/src/transformers/__init__.py
--- a/src/transformers/__init__.py
+++ b/src/transformers/__init__.py
@@ -3214,7 +3214,11 @@
     import sys
 
     sys.modules[__name__] = _LazyModule(
-        __name__, globals()["__file__"], _import_structure, extra_objects={"__version__": __version__}
+        __name__,
+        globals()["__file__"],
+        _import_structure,
+        module_spec=__spec__,
+        extra_objects={"__version__": __version__},
     )
 
 
diff --git a/src/transformers/file_utils.py b/src/transformers/file_utils.py
--- a/src/transformers/file_utils.py
+++ b/src/transformers/file_utils.py
@@ -1964,7 +1964,7 @@ class _LazyModule(ModuleType):
 
     # Very heavily inspired by optuna.integration._IntegrationModule
     # https://github.com/optuna/optuna/blob/master/optuna/integration/__init__.py
-    def __init__(self, name, module_file, import_structure, extra_objects=None):
+    def __init__(self, name, module_file, import_structure, module_spec=None, extra_objects=None):
         super().__init__(name)
         self._modules = set(import_structure.keys())
         self._class_to_module = {}
@@ -1974,6 +1974,7 @@ def __init__(self, name, module_file, import_structure, extra_objects=None):
         # Needed for autocompletion in an IDE
         self.__all__ = list(import_structure.keys()) + sum(import_structure.values(), [])
         self.__file__ = module_file
+        self.__spec__ = module_spec
         self.__path__ = [os.path.dirname(module_file)]
         self._objects = {} if extra_objects is None else extra_objects
         self._name = name


Test patch:
diff --git a/tests/test_file_utils.py b/tests/test_file_utils.py
--- a/tests/test_file_utils.py
+++ b/tests/test_file_utils.py
@@ -12,9 +12,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import importlib
 import unittest
 
 import requests
+import transformers
 
 # Try to import everything from transformers to ensure every object can be loaded.
 from transformers import *  # noqa F406
@@ -38,6 +40,11 @@
 # Sha-256 of pytorch_model.bin on the top of `main`, for checking purposes
 
 
+def test_module_spec():
+    assert transformers.__spec__ is not None
+    assert importlib.util.find_spec("transformers") is not None
+
+
 class GetFromCacheTests(unittest.TestCase):
     def test_bogus_url(self):
         # This lets us simulate no connection