Repository: mwouts/jupytext
Pull request #198 (2019-03-13 00:09:29)

1.0.3
**Improvements**

- Matlab and Octave notebooks and scripts are now supported (#197)

**BugFixes**

- `notebook_metadata_filter = "all"` now works (#196)
- Default pairing in subfolders fixed in Jupyter Lab (#180)

codecov[bot]: # [Codecov](https://codecov.io/gh/mwouts/jupytext/pull/198?src=pr&el=h1) Report
> Merging [#198](https://codecov.io/gh/mwouts/jupytext/pull/198?src=pr&el=desc) into [master](https://codecov.io/gh/mwouts/jupytext/commit/2fb5d7ad929153d79430ddbc2f97797b90a06978?src=pr&el=desc) will **decrease** coverage by `0.05%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/mwouts/jupytext/pull/198/graphs/tree.svg?width=650&token=a1pNjsiILi&height=150&src=pr)](https://codecov.io/gh/mwouts/jupytext/pull/198?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##           master    #198      +/-   ##
=========================================
- Coverage   99.46%   99.4%   -0.06%     
=========================================
  Files          62      62              
  Lines        5565    5578      +13     
=========================================
+ Hits         5535    5545      +10     
- Misses         30      33       +3
```


| [Impacted Files](https://codecov.io/gh/mwouts/jupytext/pull/198?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [jupytext/contentsmanager.py](https://codecov.io/gh/mwouts/jupytext/pull/198/diff?src=pr&el=tree#diff-anVweXRleHQvY29udGVudHNtYW5hZ2VyLnB5) | `97.29% <100%> (+0.04%)` | :arrow_up: |
| [jupytext/metadata\_filter.py](https://codecov.io/gh/mwouts/jupytext/pull/198/diff?src=pr&el=tree#diff-anVweXRleHQvbWV0YWRhdGFfZmlsdGVyLnB5) | `100% <100%> (+1.29%)` | :arrow_up: |
| [tests/test\_metadata\_filter.py](https://codecov.io/gh/mwouts/jupytext/pull/198/diff?src=pr&el=tree#diff-dGVzdHMvdGVzdF9tZXRhZGF0YV9maWx0ZXIucHk=) | `100% <100%> (ø)` | :arrow_up: |
| [jupytext/jupytext.py](https://codecov.io/gh/mwouts/jupytext/pull/198/diff?src=pr&el=tree#diff-anVweXRleHQvanVweXRleHQucHk=) | `100% <100%> (ø)` | :arrow_up: |
| [jupytext/version.py](https://codecov.io/gh/mwouts/jupytext/pull/198/diff?src=pr&el=tree#diff-anVweXRleHQvdmVyc2lvbi5weQ==) | `100% <100%> (ø)` | :arrow_up: |
| [jupytext/pep8.py](https://codecov.io/gh/mwouts/jupytext/pull/198/diff?src=pr&el=tree#diff-anVweXRleHQvcGVwOC5weQ==) | `95.23% <0%> (-4.77%)` | :arrow_down: |
| [jupytext/cell\_reader.py](https://codecov.io/gh/mwouts/jupytext/pull/198/diff?src=pr&el=tree#diff-anVweXRleHQvY2VsbF9yZWFkZXIucHk=) | `98.75% <0%> (-0.25%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/mwouts/jupytext/pull/198?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/mwouts/jupytext/pull/198?src=pr&el=footer). Last update [2fb5d7a...163e67e](https://codecov.io/gh/mwouts/jupytext/pull/198?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

mwouts: This pull request **fixes 2 alerts** when merging 8a373828beee29768776d12dddcf172350a74918 into 2fb5d7ad929153d79430ddbc2f97797b90a06978 - [view on LGTM.com](https://lgtm.com/projects/g/mwouts/jupytext/rev/pr-ff374d26241f9bcb55e29c01870d61ea4c0c0b26)

**fixed alerts:**

* 1 for Module is imported with &#39;import&#39; and &#39;import from&#39;
* 1 for Variable defined multiple times

---

*Comment posted by [LGTM.com](https://lgtm.com)*

Patch:
diff --git a/HISTORY.rst b/HISTORY.rst
index fcd64ce5..3a85fb03 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -3,6 +3,19 @@
 Release History
 ---------------
 
+1.0.3 (2019-03-13)
+++++++++++++++++++++++
+
+**Improvements**
+
+- Matlab and Octave notebooks and scripts are now supported (#197)
+
+**BugFixes**
+
+- ``notebook_metadata_filter = "all"`` now works (#196)
+- Default pairing in subfolders fixed in Jupyter Lab (#180)
+
+
 1.0.2 (2019-02-27)
 ++++++++++++++++++++++
 
diff --git a/README.md b/README.md
index 7f5296d3..1b29858c 100755
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ Have you always wished Jupyter notebooks were plain text documents? Wished you c
 
 Jupytext can save Jupyter notebooks as
 - Markdown and R Markdown documents,
-- Julia, Python, R, Bash, Scheme, Clojure, C++ and q/kdb+ scripts.
+- Julia, Python, R, Bash, Scheme, Clojure, Matlab, Octave, C++ and q/kdb+ scripts.
 
 There are multiple ways to use `jupytext`:
 - Directly from Jupyter Notebook or JupyterLab. Jupytext provides a _contents manager_ that allows Jupyter to save your notebook to your favorite format (`.py`, `.R`, `.jl`, `.md`, `.Rmd`...) in addition to (or in place of) the traditional `.ipynb` file. The text representation can be edited in your favorite editor. When you're done, refresh the notebook in Jupyter: inputs cells are loaded from the text file, while output cells are reloaded from the `.ipynb` file if present. Refreshing preserves kernel variables, so you can resume your work in the notebook and run the modified cells without having to rerun the notebook in full.
@@ -349,7 +349,7 @@ The `light` format has:
 - Code cells are exported verbatim (except for Jupyter magics, which are commented), and separated with blank lines. Code cells are reconstructed from consistent Python paragraphs (no function, class or multiline comment will be broken).
 - Cells that contain more than one Python paragraphs need an explicit start-of-cell delimiter `# +` (`// +` in C++, etc). Cells that have explicit metadata have a cell header `# + {JSON}` where the metadata is represented, in JSON format. The end of cell delimiter is `# -`, and is omitted when followed by another explicit start of cell marker.
 
-The `light` format is currently available for Python, Julia, R, Bash, Scheme, Clojure, C++ and q/kdb+. Open our sample notebook in the `light` format [here](https://github.com/mwouts/jupytext/blob/master/demo/World%20population.lgt.py).
+The `light` format is currently available for Python, Julia, R, Bash, Scheme, Clojure, Matlab, Octave, C++ and q/kdb+. Open our sample notebook in the `light` format [here](https://github.com/mwouts/jupytext/blob/master/demo/World%20population.lgt.py).
 
 A variation of the `light` format is the `bare` format, with no cell marker at all. Please note that this format will split your code cells on code paragraphs. By default, this format still includes a YAML header - if you prefer to also remove the header, set `"notebook_metadata_filter": "-all"` in the jupytext section of your notebook metadata.  
 
@@ -370,7 +370,7 @@ where cell type is either omitted (code cells), or `[markdown]` or  `[raw]`. The
 
 Percent scripts created by Jupytext have a header with an explicit format information. The format of scripts with no header is inferred automatically: scripts with at least one `# %%` cell are identified as `percent` scripts. Scripts with at least one double percent cell, and an uncommented Jupyter magic command, are identified as `hydrogen` scripts.
 
-The `percent` format is currently available for Python, Julia, R, Bash, Scheme, Clojure, C++ and q/kdb+. Open our sample notebook in the `percent` format [here](https://github.com/mwouts/jupytext/blob/master/demo/World%20population.pct.py).
+The `percent` format is currently available for Python, Julia, R, Bash, Scheme, Clojure, Matlab, Octave, C++ and q/kdb+. Open our sample notebook in the `percent` format [here](https://github.com/mwouts/jupytext/blob/master/demo/World%20population.pct.py).
 
 If the `percent` format is your favorite one, add the following to your `.jupyter/jupyter_notebook_config.py` file:
 ```python
diff --git a/conf.py b/conf.py
index 3ef994f9..2ca1831c 100644
--- a/conf.py
+++ b/conf.py
@@ -71,8 +71,7 @@ language = None
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
 # This pattern also affects html_static_path and html_extra_path.
-exclude_patterns = ['.build', 'Thumbs.db', '.DS_Store']
-exclude_patterns = ['tests', 'demo', 'venv', '.*cache']
+exclude_patterns = ['.build', 'Thumbs.db', '.DS_Store', 'tests', 'demo', 'venv', '.*cache']
 
 # The name of the Pygments (syntax highlighting) style to use.
 pygments_style = None
diff --git a/jupytext/contentsmanager.py b/jupytext/contentsmanager.py
index 1020fa3e..4a0287e4 100644
--- a/jupytext/contentsmanager.py
+++ b/jupytext/contentsmanager.py
@@ -17,8 +17,7 @@ except ImportError:
 from notebook.services.contents.filemanager import FileContentsManager
 from jupyter_client.kernelspec import find_kernel_specs, get_kernel_spec
 
-import jupytext
-from .jupytext import create_prefix_dir
+from .jupytext import reads, writes, create_prefix_dir
 from .combine import combine_inputs_with_outputs
 from .formats import rearrange_jupytext_metadata, check_file_version
 from .formats import NOTEBOOK_EXTENSIONS, long_form_one_format, long_form_multiple_formats
@@ -58,14 +57,14 @@ def preferred_format(incomplete_format, preferred_formats):
 
 def _jupytext_writes(fmt):
     def _writes(nbk, version=nbformat.NO_CONVERT, **kwargs):
-        return jupytext.writes(nbk, fmt, version=version, **kwargs)
+        return writes(nbk, fmt, version=version, **kwargs)
 
     return _writes
 
 
 def _jupytext_reads(fmt):
     def _reads(text, as_version, **kwargs):
-        return jupytext.reads(text, fmt, as_version=as_version, **kwargs)
+        return reads(text, fmt, as_version=as_version, **kwargs)
 
     return _reads
 
@@ -237,7 +236,7 @@ class TextFileContentsManager(FileContentsManager, Configurable):
             self.update_paired_notebooks(path, fmt, jupytext_formats)
 
             # Save as ipynb first
-            latest_result = None
+            return_value = None
             for fmt in jupytext_formats[::-1]:
                 if fmt['extension'] != '.ipynb':
                     continue
@@ -245,7 +244,9 @@ class TextFileContentsManager(FileContentsManager, Configurable):
                 alt_path = full_path(base, fmt)
                 self.create_prefix_dir(alt_path, fmt)
                 self.log.info("Saving %s", os.path.basename(alt_path))
-                latest_result = super(TextFileContentsManager, self).save(model, alt_path)
+                value = super(TextFileContentsManager, self).save(model, alt_path)
+                if alt_path == path:
+                    return_value = value
 
             # And then to the other formats, in reverse order so that
             # the first format is the most recent
@@ -262,9 +263,11 @@ class TextFileContentsManager(FileContentsManager, Configurable):
                 else:
                     self.log.info("Saving %s", os.path.basename(alt_path))
                 with mock.patch('nbformat.writes', _jupytext_writes(fmt)):
-                    latest_result = super(TextFileContentsManager, self).save(model, alt_path)
+                    value = super(TextFileContentsManager, self).save(model, alt_path)
+                    if alt_path == path:
+                        return_value = value
 
-            return latest_result
+            return return_value
 
         except Exception as err:
             raise HTTPError(400, str(err))
diff --git a/jupytext/jupytext.py b/jupytext/jupytext.py
index 0e86c6fa..1d0c53bd 100644
--- a/jupytext/jupytext.py
+++ b/jupytext/jupytext.py
@@ -262,7 +262,7 @@ def writef(notebook, nb_file, fmt=None):
 def create_prefix_dir(nb_file, fmt):
     """Create directory if fmt has a prefix"""
     if 'prefix' in fmt:
-        nb_dir = os.path.dirname(nb_file)
+        nb_dir = os.path.dirname(nb_file) + os.path.sep
         if not os.path.isdir(nb_dir):
             logging.log(logging.WARNING, "[jupytext] creating missing directory %s", nb_dir)
             os.makedirs(nb_dir)
diff --git a/jupytext/languages.py b/jupytext/languages.py
index 6c3cf599..a30adce5 100644
--- a/jupytext/languages.py
+++ b/jupytext/languages.py
@@ -1,7 +1,7 @@
 """Determine notebook or cell language"""
 
 _JUPYTER_LANGUAGES = ['R', 'bash', 'sh', 'python', 'python2', 'python3', 'javascript', 'js', 'perl',
-                      'html', 'latex', 'markdown', 'pypy', 'ruby', 'script', 'svg', 'writefile']
+                      'html', 'latex', 'markdown', 'pypy', 'ruby', 'script', 'svg', 'writefile', 'matlab', 'octave']
 
 _SCRIPT_EXTENSIONS = {'.py': {'language': 'python', 'comment': '#'},
                       '.R': {'language': 'R', 'comment': '#'},
@@ -12,7 +12,8 @@ _SCRIPT_EXTENSIONS = {'.py': {'language': 'python', 'comment': '#'},
                       '.clj': {'language': 'clojure', 'comment': ';;'},
                       '.scm': {'language': 'scheme', 'comment': ';;'},
                       '.sh': {'language': 'bash', 'comment': '#'},
-                      '.q': {'language': 'q', 'comment': '/'}}
+                      '.q': {'language': 'q', 'comment': '/'},
+                      '.m': {'language': 'matlab', 'comment': '%'}}
 
 _COMMENT_CHARS = [_SCRIPT_EXTENSIONS[ext]['comment'] for ext in _SCRIPT_EXTENSIONS if
                   _SCRIPT_EXTENSIONS[ext]['comment'] != '#']
diff --git a/jupytext/magics.py b/jupytext/magics.py
index 3704673f..31cb5967 100644
--- a/jupytext/magics.py
+++ b/jupytext/magics.py
@@ -27,6 +27,8 @@ _PYTHON_MAGIC_CMD = re.compile(r"^(# |#)*({})(\s|$)".format('|'.join(
 
 def is_magic(line, language, global_escape_flag=True):
     """Is the current line a (possibly escaped) Jupyter magic, and should it be commented?"""
+    if language in ['octave', 'matlab']:
+        return False
     if _MAGIC_FORCE_ESC_RE.get(language, _MAGIC_FORCE_ESC_RE['python']).match(line):
         return True
     if not global_escape_flag or _MAGIC_NOT_ESC_RE.get(language, _MAGIC_NOT_ESC_RE['python']).match(line):
diff --git a/jupytext/metadata_filter.py b/jupytext/metadata_filter.py
index 1b043402..d54ca9aa 100644
--- a/jupytext/metadata_filter.py
+++ b/jupytext/metadata_filter.py
@@ -103,7 +103,7 @@ def apply_metadata_filters(user_filter, default_filter, actual_keys):
 
     # notebook default filter = only few metadata
     if default_filter.get('additional'):
-        if user_filter.get('excluded') == 'all':
+        if user_filter.get('additional') == 'all':
             return actual_keys.difference(user_filter.get('excluded'))
 
         return (actual_keys
diff --git a/jupytext/version.py b/jupytext/version.py
index 5ffbce13..42e038d1 100644
--- a/jupytext/version.py
+++ b/jupytext/version.py
@@ -1,3 +1,3 @@
 """Jupytext's version number"""
 
-__version__ = '1.0.2'
+__version__ = '1.0.3'


Test patch:
diff --git a/tests/notebooks/ipynb_m/octave_notebook.ipynb b/tests/notebooks/ipynb_m/octave_notebook.ipynb
new file mode 100644
index 00000000..3f574925
--- /dev/null
+++ b/tests/notebooks/ipynb_m/octave_notebook.ipynb
@@ -0,0 +1,171 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A markdown cell"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "ans =  2\n"
+     ]
+    }
+   ],
+   "source": [
+    "1 + 1"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "ans =  4\n"
+     ]
+    }
+   ],
+   "source": [
+    "% a code cell with comments\n",
+    "2 + 2"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "image/png": "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\n",
+      "text/plain": [
+       "<IPython.core.display.Image object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "% a simple plot\n",
+    "x = -10:0.1:10;\n",
+    "plot (x, sin (x));"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "image/png": "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\n",
+      "text/plain": [
+       "<IPython.core.display.Image object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%plot -w 800\n",
+    "% a simple plot with a magic instruction\n",
+    "x = -10:0.1:10;\n",
+    "plot (x, sin (x));"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "And to finish with, a Python cell"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%%python\n",
+    "a = 1"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "2"
+      ]
+     },
+     "execution_count": 6,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "%%python\n",
+    "a + 1"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Octave",
+   "language": "octave",
+   "name": "octave"
+  },
+  "language_info": {
+   "file_extension": ".m",
+   "help_links": [
+    {
+     "text": "GNU Octave",
+     "url": "https://www.gnu.org/software/octave/support.html"
+    },
+    {
+     "text": "Octave Kernel",
+     "url": "https://github.com/Calysto/octave_kernel"
+    },
+    {
+     "text": "MetaKernel Magics",
+     "url": "https://github.com/calysto/metakernel/blob/master/metakernel/magics/README.md"
+    }
+   ],
+   "mimetype": "text/x-octave",
+   "name": "octave",
+   "version": "4.2.2"
+  },
+  "toc": {
+   "base_numbering": 1,
+   "nav_menu": {},
+   "number_sections": true,
+   "sideBar": true,
+   "skip_h1_title": false,
+   "title_cell": "Table of Contents",
+   "title_sidebar": "Contents",
+   "toc_cell": false,
+   "toc_position": {},
+   "toc_section_display": true,
+   "toc_window_display": false
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/tests/notebooks/mirror/ipynb_to_percent/octave_notebook.m b/tests/notebooks/mirror/ipynb_to_percent/octave_notebook.m
new file mode 100644
index 00000000..859f4954
--- /dev/null
+++ b/tests/notebooks/mirror/ipynb_to_percent/octave_notebook.m
@@ -0,0 +1,37 @@
+% ---
+% jupyter:
+%   kernelspec:
+%     display_name: Octave
+%     language: octave
+%     name: octave
+% ---
+
+% %% [markdown]
+% A markdown cell
+
+% %%
+1 + 1
+
+% %%
+% a code cell with comments
+2 + 2
+
+% %%
+% a simple plot
+x = -10:0.1:10;
+plot (x, sin (x));
+
+% %%
+%plot -w 800
+% a simple plot with a magic instruction
+x = -10:0.1:10;
+plot (x, sin (x));
+
+% %% [markdown]
+% And to finish with, a Python cell
+
+% %% {"language": "python"}
+% a = 1
+
+% %% {"language": "python"}
+% a + 1
diff --git a/tests/notebooks/mirror/ipynb_to_script/octave_notebook.m b/tests/notebooks/mirror/ipynb_to_script/octave_notebook.m
new file mode 100644
index 00000000..e6faacb2
--- /dev/null
+++ b/tests/notebooks/mirror/ipynb_to_script/octave_notebook.m
@@ -0,0 +1,31 @@
+% ---
+% jupyter:
+%   kernelspec:
+%     display_name: Octave
+%     language: octave
+%     name: octave
+% ---
+
+% A markdown cell
+
+1 + 1
+
+% a code cell with comments
+2 + 2
+
+% a simple plot
+x = -10:0.1:10;
+plot (x, sin (x));
+
+%plot -w 800
+% a simple plot with a magic instruction
+x = -10:0.1:10;
+plot (x, sin (x));
+
+% And to finish with, a Python cell
+
+% + {"language": "python"}
+% a = 1
+
+% + {"language": "python"}
+% a + 1
diff --git a/tests/test_metadata_filter.py b/tests/test_metadata_filter.py
index 9b8b30eb..db3785eb 100644
--- a/tests/test_metadata_filter.py
+++ b/tests/test_metadata_filter.py
@@ -1,4 +1,5 @@
 import pytest
+from nbformat.v4.nbbase import new_notebook
 from jupytext import reads, writes
 from jupytext.metadata_filter import filter_metadata, metadata_filter_as_dict
 
@@ -68,3 +69,16 @@ jupyter:
 
     text2 = writes(nb, 'Rmd')
     assert text.splitlines()[-3:] == text2.splitlines()[-3:]
+
+
+def test_notebook_metadata_all():
+    nb = new_notebook(metadata={'user_metadata': [1, 2, 3],
+                                'jupytext': {'notebook_metadata_filter': 'all'}})
+    text = writes(nb, 'md')
+    assert 'user_metadata' in text
+
+
+def test_notebook_metadata_none():
+    nb = new_notebook(metadata={'jupytext': {'notebook_metadata_filter': '-all'}})
+    text = writes(nb, 'md')
+    assert '---' not in text
diff --git a/tests/test_mirror.py b/tests/test_mirror.py
index 34c1229e..7dddc9c2 100644
--- a/tests/test_mirror.py
+++ b/tests/test_mirror.py
@@ -109,6 +109,11 @@ def test_ipynb_to_r(nb_file):
     assert_conversion_same_as_mirror(nb_file, '.low.r', 'ipynb_to_script')
 
 
+@pytest.mark.parametrize('nb_file', list_notebooks('ipynb_m'))
+def test_ipynb_to_m(nb_file):
+    assert_conversion_same_as_mirror(nb_file, '.m', 'ipynb_to_script')
+
+
 @pytest.mark.parametrize('nb_file,extension',
                          [(nb_file, extension)
                           for nb_file in list_notebooks('ipynb_scheme')
@@ -142,6 +147,11 @@ def test_ipynb_to_julia_percent(nb_file):
     assert_conversion_same_as_mirror(nb_file, 'jl:percent', 'ipynb_to_percent')
 
 
+@pytest.mark.parametrize('nb_file', list_notebooks('ipynb_m'))
+def test_ipynb_to_m_percent(nb_file):
+    assert_conversion_same_as_mirror(nb_file, 'm:percent', 'ipynb_to_percent')
+
+
 @pytest.mark.parametrize('nb_file', list_notebooks('ipynb_py', skip=''))
 def test_ipynb_to_python_percent(nb_file):
     assert_conversion_same_as_mirror(nb_file, 'py:percent', 'ipynb_to_percent')