Repository: getnikola/nikola

Issue:
Unable to use Jupyter Notebook compiler
<!--
Before creating an issue:
* make sure you are using an up-to-date version of Nikola
* search for existing issues that might be related

If you are reporting a bug:
* provide information about your environment (below)
* include all the output you get, and any other information related to your problem

Nikola v7.6.4, as provided by Debian/Ubuntu, is NOT SUPPORTED.
If you are using this version, you should upgrade: https://getnikola.com/getting-started.html
-->

### Environment (if reporting a bug)

**Python Version: Python 3.5.3**

**Nikola Version: Nikola v7.8.4**

**Operating System: Fedora 25 x86_64**

### Description:

I cannot enable Jupyter notebook compiler, this is the output of `nikola -V`  
```

[2017-04-23T16:38:22Z] ERROR: yapsy: Unable to import plugin: /usr/lib/python3.5/site-packages/nikola/plugins/compile/ipynb
Traceback (most recent call last):
  File "/usr/lib/python3.5/site-packages/yapsy/PluginManager.py", line 488, in loadPlugins
    candidate_module = imp.load_module(plugin_module_name,plugin_file,candidate_filepath+".py",("py","r",imp.PY_SOURCE))
  File "/usr/lib64/python3.5/imp.py", line 234, in load_module
    return load_source(name, filename, file)
  File "/usr/lib64/python3.5/imp.py", line 172, in load_source
    module = _load(spec)
  File "<frozen importlib._bootstrap>", line 693, in _load
  File "<frozen importlib._bootstrap>", line 673, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 697, in exec_module
  File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed
  File "/usr/lib/python3.5/site-packages/nikola/plugins/compile/ipynb.py", line 36, in <module>
    from nbconvert.exporters import HTMLExporter
  File "/usr/lib/python3.5/site-packages/nbconvert/__init__.py", line 4, in <module>
    from .exporters import *
  File "/usr/lib/python3.5/site-packages/nbconvert/exporters/__init__.py", line 1, in <module>
    from .base import (export, get_exporter,
  File "/usr/lib/python3.5/site-packages/nbconvert/exporters/base.py", line 16, in <module>
    from .exporter import Exporter
  File "/usr/lib/python3.5/site-packages/nbconvert/exporters/exporter.py", line 47, in <module>
    class Exporter(LoggingConfigurable):
  File "/usr/lib/python3.5/site-packages/nbconvert/exporters/exporter.py", line 55, in Exporter
    help="Extension of the file that should be written to disk"
AttributeError: 'FilenameExtension' object has no attribute 'tag'
Nikola v7.8.4
```
Please: could you help me? I can't use .ipynb files :(

Thanks in advance!




Discussion:
Did you install Jupyter from dnf? What does `jupyter --version` say?
Thanks @Kwpolska yup, I had installed jupyter from dnf. So, I've removed and now ipynb compiler works.
Greetings
Perhaps we could make things clearer here? We have some support code for older versions, but at the same time, requirements.txt says >=4.0.
@Kwpolska you mean a doc fix? Is there anything left to do in this issue?
We should drop code that provides support for older ipynb/jupyter versions from ipynb.py.

Resolving patch:
diff --git a/nikola/plugins/compile/ipynb.py b/nikola/plugins/compile/ipynb.py
--- a/nikola/plugins/compile/ipynb.py
+++ b/nikola/plugins/compile/ipynb.py
@@ -39,27 +39,8 @@
     from jupyter_client import kernelspec
     from traitlets.config import Config
     flag = True
-    ipy_modern = True
 except ImportError:
-    try:
-        import IPython
-        from IPython.nbconvert.exporters import HTMLExporter
-        if IPython.version_info[0] >= 3:     # API changed with 3.0.0
-            from IPython import nbformat
-            current_nbformat = nbformat.current_nbformat
-            from IPython.kernel import kernelspec
-            ipy_modern = True
-        else:
-            import IPython.nbformat.current as nbformat
-            current_nbformat = 'json'
-            kernelspec = None
-            ipy_modern = False
-
-        from IPython.config import Config
-        flag = True
-    except ImportError:
-        flag = None
-        ipy_modern = None
+    flag = None
 
 from nikola import shortcodes as sc
 from nikola.plugin_categories import PageCompiler
@@ -81,8 +62,7 @@ def set_site(self, site):
 
     def _compile_string(self, nb_json):
         """Export notebooks as HTML strings."""
-        if flag is None:
-            req_missing(['ipython[notebook]>=2.0.0'], 'build this site (compile ipynb)')
+        self._req_missing_ipynb()
         c = Config(self.site.config['IPYNB_CONFIG'])
         c.update(get_default_jupyter_config())
         exportHtml = HTMLExporter(config=c)
@@ -93,6 +73,10 @@ def _compile_string(self, nb_json):
     def _nbformat_read(in_file):
         return nbformat.read(in_file, current_nbformat)
 
+    def _req_missing_ipynb(self):
+        if flag is None:
+            req_missing(['notebook>=4.0.0'], 'build this site (compile ipynb)')
+
     def compile_string(self, data, source_path=None, is_two_file=True, post=None, lang=None):
         """Compile notebooks into HTML strings."""
         new_data, shortcodes = sc.extract_shortcodes(data)
@@ -128,8 +112,7 @@ def read_metadata(self, post, file_metadata_regexp=None, unslugify_titles=False,
         As ipynb file support arbitrary metadata as json, the metadata used by Nikola
         will be assume to be in the 'nikola' subfield.
         """
-        if flag is None:
-            req_missing(['ipython[notebook]>=2.0.0'], 'build this site (compile ipynb)')
+        self._req_missing_ipynb()
         source = post.source_path
         with io.open(source, "r", encoding="utf8") as in_file:
             nb_json = nbformat.read(in_file, current_nbformat)
@@ -139,8 +122,7 @@ def read_metadata(self, post, file_metadata_regexp=None, unslugify_titles=False,
 
     def create_post(self, path, **kw):
         """Create a new post."""
-        if flag is None:
-            req_missing(['ipython[notebook]>=2.0.0'], 'build this site (compile ipynb)')
+        self._req_missing_ipynb()
         content = kw.pop('content', None)
         onefile = kw.pop('onefile', False)
         kernel = kw.pop('ipython_kernel', None)
@@ -157,12 +139,8 @@ def create_post(self, path, **kw):
             # imported .ipynb file, guaranteed to start with "{" because it’s JSON.
             nb = nbformat.reads(content, current_nbformat)
         else:
-            if ipy_modern:
-                nb = nbformat.v4.new_notebook()
-                nb["cells"] = [nbformat.v4.new_markdown_cell(content)]
-            else:
-                nb = nbformat.new_notebook()
-                nb["worksheets"] = [nbformat.new_worksheet(cells=[nbformat.new_text_cell('markdown', [content])])]
+            nb = nbformat.v4.new_notebook()
+            nb["cells"] = [nbformat.v4.new_markdown_cell(content)]
 
             if kernelspec is not None:
                 if kernel is None:
@@ -190,10 +168,7 @@ def create_post(self, path, **kw):
             nb["metadata"]["nikola"] = metadata
 
         with io.open(path, "w+", encoding="utf8") as fd:
-            if ipy_modern:
-                nbformat.write(nb, fd, 4)
-            else:
-                nbformat.write(nb, fd, 'ipynb')
+            nbformat.write(nb, fd, 4)
 
 
 def get_default_jupyter_config():


Test patch: