Repository: explosion/spaCy

Issue:
importlib module_from_spec error in Python 3.4
I download models like this
python -m spacy download en
python -m spacy download en_core_web_md

Above commands create a link like this 



 Linking successful
    /home/sameer/anaconda2/envs/py34/lib/python3.4/site-packages/en_core_web_md
    -->
    /home/sameer/anaconda2/envs/py34/lib/python3.4/site-packages/spacy/data/en_core_web_md

    You can now load the model via spacy.load('en_core_web_md')




But when I actually load the model ,it throws the following error 


>>> import spacy
>>> nlp= spacy.load('en_core_web_md')
Traceback (most recent call last):
  File "/home/sameer/anaconda2/envs/py34/lib/python3.4/site-packages/spacy/util.py", line 126, in load_model_from_link
    cls = import_file(name, path)
  File "/home/sameer/anaconda2/envs/py34/lib/python3.4/site-packages/spacy/compat.py", line 118, in import_file
    module = importlib.util.module_from_spec(spec)
AttributeError: 'module' object has no attribute 'module_from_spec'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/sameer/anaconda2/envs/py34/lib/python3.4/site-packages/spacy/__init__.py", line 19, in load
    return util.load_model(name, **overrides)
  File "/home/sameer/anaconda2/envs/py34/lib/python3.4/site-packages/spacy/util.py", line 112, in load_model
    return load_model_from_link(name, **overrides)
  File "/home/sameer/anaconda2/envs/py34/lib/python3.4/site-packages/spacy/util.py", line 130, in load_model_from_link
    "points to a valid package (not just a data directory)." % name)
OSError: Cant' load 'en_core_web_md'. If you're using a shortcut link, make sure it points to a valid package (not just a data directory).
>>> 









## Your Environment
<!-- Include details of your environment. If you're using spaCy 1.7+, you can also type 
`python -m spacy info --markdown` and copy-paste the result here.-->* **Python version:** 3.4.5
* **Platform:** Linux-4.4.0-101-generic-x86_64-with-debian-jessie-sid
* **Models:** __cache__, en_core_web_md, en, en-1.1.0
* **spaCy version:** 2.0.5

* Operating System: Ububtu 14.04
* Python Version Used: 3.4.5
* spaCy Version Used: 2.0.5
* Environment Information: Conda Virtual Environment

importlib module_from_spec error in Python 3.4
I download models like this
python -m spacy download en
python -m spacy download en_core_web_md

Above commands create a link like this 



 Linking successful
    /home/sameer/anaconda2/envs/py34/lib/python3.4/site-packages/en_core_web_md
    -->
    /home/sameer/anaconda2/envs/py34/lib/python3.4/site-packages/spacy/data/en_core_web_md

    You can now load the model via spacy.load('en_core_web_md')




But when I actually load the model ,it throws the following error 


>>> import spacy
>>> nlp= spacy.load('en_core_web_md')
Traceback (most recent call last):
  File "/home/sameer/anaconda2/envs/py34/lib/python3.4/site-packages/spacy/util.py", line 126, in load_model_from_link
    cls = import_file(name, path)
  File "/home/sameer/anaconda2/envs/py34/lib/python3.4/site-packages/spacy/compat.py", line 118, in import_file
    module = importlib.util.module_from_spec(spec)
AttributeError: 'module' object has no attribute 'module_from_spec'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/sameer/anaconda2/envs/py34/lib/python3.4/site-packages/spacy/__init__.py", line 19, in load
    return util.load_model(name, **overrides)
  File "/home/sameer/anaconda2/envs/py34/lib/python3.4/site-packages/spacy/util.py", line 112, in load_model
    return load_model_from_link(name, **overrides)
  File "/home/sameer/anaconda2/envs/py34/lib/python3.4/site-packages/spacy/util.py", line 130, in load_model_from_link
    "points to a valid package (not just a data directory)." % name)
OSError: Cant' load 'en_core_web_md'. If you're using a shortcut link, make sure it points to a valid package (not just a data directory).
>>> 









## Your Environment
<!-- Include details of your environment. If you're using spaCy 1.7+, you can also type 
`python -m spacy info --markdown` and copy-paste the result here.-->* **Python version:** 3.4.5
* **Platform:** Linux-4.4.0-101-generic-x86_64-with-debian-jessie-sid
* **Models:** __cache__, en_core_web_md, en, en-1.1.0
* **spaCy version:** 2.0.5

* Operating System: Ububtu 14.04
* Python Version Used: 3.4.5
* spaCy Version Used: 2.0.5
* Environment Information: Conda Virtual Environment



Discussion:
Thanks for the report!

> `AttributeError: 'module' object has no attribute 'module_from_spec'`

It looks like the linking itself worked fine – but the problem here is that [importlib's `module_from_spec`](https://docs.python.org/3/library/importlib.html#importlib.util.module_from_spec), which spaCy uses to load model packages from paths, only exists in Python 3.5, not 3.4. We do have a [workaround for this in the `spacy.compat`](https://github.com/explosion/spaCy/blob/master/spacy/compat.py#L53) module, but this seems to only target Python 2 vs. Python 3. (I guess since 3.4 is less commonly used, this hasn't come up before).

If you don't want to dig into the source and don't want to / can't upgrade to Python 3.5, the easiest workaround for now would be to simply [import the model as a module](https://spacy.io/usage/models#usage-import) and call its `load()` method. Since the model is installed as a package, this works just as well:

```python
import en_core_web_md
nlp = en_core_web_md.load()
```
Thanks for the report!

> `AttributeError: 'module' object has no attribute 'module_from_spec'`

It looks like the linking itself worked fine – but the problem here is that [importlib's `module_from_spec`](https://docs.python.org/3/library/importlib.html#importlib.util.module_from_spec), which spaCy uses to load model packages from paths, only exists in Python 3.5, not 3.4. We do have a [workaround for this in the `spacy.compat`](https://github.com/explosion/spaCy/blob/master/spacy/compat.py#L53) module, but this seems to only target Python 2 vs. Python 3. (I guess since 3.4 is less commonly used, this hasn't come up before).

If you don't want to dig into the source and don't want to / can't upgrade to Python 3.5, the easiest workaround for now would be to simply [import the model as a module](https://spacy.io/usage/models#usage-import) and call its `load()` method. Since the model is installed as a package, this works just as well:

```python
import en_core_web_md
nlp = en_core_web_md.load()
```

Resolving patch:
diff --git a/spacy/compat.py b/spacy/compat.py
--- a/spacy/compat.py
+++ b/spacy/compat.py
@@ -43,15 +43,15 @@
 copy_array = copy_array
 izip = getattr(itertools, 'izip', zip)
 
-is_python2 = six.PY2
-is_python3 = six.PY3
 is_windows = sys.platform.startswith('win')
 is_linux = sys.platform.startswith('linux')
 is_osx = sys.platform == 'darwin'
 
+is_python2 = six.PY2
+is_python3 = six.PY3
+is_python_pre_3_5 = is_python2 or (is_python3 and sys.version_info[1]<5)
 
 if is_python2:
-    import imp
     bytes_ = str
     unicode_ = unicode  # noqa: F821
     basestring_ = basestring  # noqa: F821
@@ -60,7 +60,6 @@
     path2str = lambda path: str(path).decode('utf8')
 
 elif is_python3:
-    import importlib.util
     bytes_ = bytes
     unicode_ = str
     basestring_ = str
@@ -111,9 +110,11 @@ def normalize_string_keys(old):
 
 def import_file(name, loc):
     loc = str(loc)
-    if is_python2:
+    if is_python_pre_3_5:
+        import imp
         return imp.load_source(name, loc)
     else:
+        import importlib.util
         spec = importlib.util.spec_from_file_location(name, str(loc))
         module = importlib.util.module_from_spec(spec)
         spec.loader.exec_module(module)


Test patch: