Repository: mwouts/jupytext
Pull request #204 (2019-03-19 23:42:53)

1.0.4
**Improvements**

- Wildcard are now supported on Windows (#202)
- Trusted notebooks remain trusted when inputs cells are modified (#203)

**BugFixes**

- Pre-commit mode adds the result of conversion to the commit (#200)

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

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

```diff
@@            Coverage Diff             @@
##           master     #204      +/-   ##
==========================================
- Coverage   99.48%   99.41%   -0.07%     
==========================================
  Files          62       62              
  Lines        5583     5630      +47     
==========================================
+ Hits         5554     5597      +43     
- Misses         29       33       +4
```


| [Impacted Files](https://codecov.io/gh/mwouts/jupytext/pull/204?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [tests/test\_cli.py](https://codecov.io/gh/mwouts/jupytext/pull/204/diff?src=pr&el=tree#diff-dGVzdHMvdGVzdF9jbGkucHk=) | `100% <100%> (ø)` | :arrow_up: |
| [tests/test\_trust\_notebook.py](https://codecov.io/gh/mwouts/jupytext/pull/204/diff?src=pr&el=tree#diff-dGVzdHMvdGVzdF90cnVzdF9ub3RlYm9vay5weQ==) | `100% <100%> (ø)` | :arrow_up: |
| [jupytext/contentsmanager.py](https://codecov.io/gh/mwouts/jupytext/pull/204/diff?src=pr&el=tree#diff-anVweXRleHQvY29udGVudHNtYW5hZ2VyLnB5) | `97.29% <100%> (+0.01%)` | :arrow_up: |
| [jupytext/cli.py](https://codecov.io/gh/mwouts/jupytext/pull/204/diff?src=pr&el=tree#diff-anVweXRleHQvY2xpLnB5) | `95.98% <100%> (+0.08%)` | :arrow_up: |
| [jupytext/version.py](https://codecov.io/gh/mwouts/jupytext/pull/204/diff?src=pr&el=tree#diff-anVweXRleHQvdmVyc2lvbi5weQ==) | `100% <100%> (ø)` | :arrow_up: |
| [jupytext/pep8.py](https://codecov.io/gh/mwouts/jupytext/pull/204/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/204/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/204?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/204?src=pr&el=footer). Last update [cf6b2f1...2e631a8](https://codecov.io/gh/mwouts/jupytext/pull/204?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/HISTORY.rst b/HISTORY.rst
index 3a85fb03..25f26298 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -3,6 +3,19 @@
 Release History
 ---------------
 
+1.0.4 (2019-03-20)
+++++++++++++++++++++++
+
+**Improvements**
+
+- Wildcard are now supported on Windows (#202)
+- Trusted notebooks remain trusted when inputs cells are modified (#203)
+
+**BugFixes**
+
+- Pre-commit mode adds the result of conversion to the commit (#200)
+
+
 1.0.3 (2019-03-13)
 ++++++++++++++++++++++
 
diff --git a/jupytext/cli.py b/jupytext/cli.py
index 038fd800..47f8ca66 100644
--- a/jupytext/cli.py
+++ b/jupytext/cli.py
@@ -3,6 +3,7 @@
 import os
 import re
 import sys
+import glob
 import subprocess
 import argparse
 import json
@@ -23,7 +24,7 @@ def system(*args, **kwargs):
     out, _ = proc.communicate()
     if proc.returncode:
         raise SystemExit(proc.returncode)
-    return out
+    return out.decode('utf-8')
 
 
 def str2bool(value):
@@ -164,9 +165,9 @@ def jupytext(args=None):
             log(nb_file)
 
     def writef_git_add(notebook_, nb_file_, fmt_):
-        if args.pre_commit:
-            system('git', 'add', nb_file)
         writef(notebook_, nb_file_, fmt_)
+        if args.pre_commit:
+            system('git', 'add', nb_file_)
 
     # Read notebook from stdin
     if not args.notebooks:
@@ -202,7 +203,16 @@ def jupytext(args=None):
 
     # Main loop
     round_trip_conversion_errors = 0
-    for nb_file in args.notebooks:
+
+    # Wildcard extension on Windows #202
+    notebooks = []
+    for pattern in args.notebooks:
+        if '*' in pattern or '?' in pattern:
+            notebooks.extend(glob.glob(pattern))
+        else:
+            notebooks.append(pattern)
+
+    for nb_file in notebooks:
         if nb_file == '-' and args.sync:
             raise ValueError('Cannot sync a notebook on stdin')
 
@@ -321,7 +331,7 @@ def jupytext(args=None):
 
 def notebooks_in_git_index(fmt):
     """Return the list of modified and deleted ipynb files in the git index that match the given format"""
-    git_status = system('git', 'status', '--porcelain').decode('utf-8')
+    git_status = system('git', 'status', '--porcelain')
     re_modified = re.compile(r'^[AM]+\s+(?P<name>.*)', re.MULTILINE)
     modified_files_in_git_index = re_modified.findall(git_status)
     files = []
diff --git a/jupytext/contentsmanager.py b/jupytext/contentsmanager.py
index 4a0287e4..194a1736 100644
--- a/jupytext/contentsmanager.py
+++ b/jupytext/contentsmanager.py
@@ -394,8 +394,10 @@ class TextFileContentsManager(FileContentsManager, Configurable):
                 if kernelspec:
                     nbk.metadata['kernelspec'] = kernelspec
 
-            self.notary.sign(nbk)
-            self.mark_trusted_cells(nbk, path)
+        # Trust code cells when they have no output
+        for cell in model['content'].cells:
+            if cell.cell_type == 'code' and not cell.outputs and cell.metadata.get('trusted') is False:
+                cell.metadata['trusted'] = True
 
         # Path and name of the notebook is the one of the original path
         model['path'] = org_model['path']
diff --git a/jupytext/version.py b/jupytext/version.py
index 42e038d1..678e2e73 100644
--- a/jupytext/version.py
+++ b/jupytext/version.py
@@ -1,3 +1,3 @@
 """Jupytext's version number"""
 
-__version__ = '1.0.3'
+__version__ = '1.0.4'


Test patch:
diff --git a/tests/test_cli.py b/tests/test_cli.py
index 564a118b..362a2709 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -74,6 +74,26 @@ def test_jupytext_version(capsys):
     compare(out, __version__ + '\n')
 
 
+def test_wildcard(tmpdir):
+    nb1_ipynb = str(tmpdir.join('nb1.ipynb'))
+    nb2_ipynb = str(tmpdir.join('nb2.ipynb'))
+
+    nb1_py = str(tmpdir.join('nb1.py'))
+    nb2_py = str(tmpdir.join('nb2.py'))
+
+    writef(new_notebook(metadata={'notebook': 1}), nb1_ipynb)
+    writef(new_notebook(metadata={'notebook': 2}), nb2_ipynb)
+
+    os.chdir(str(tmpdir))
+    jupytext(['nb*.ipynb', '--to', 'py'])
+
+    assert os.path.isfile(nb1_py)
+    assert os.path.isfile(nb2_py)
+
+    with pytest.raises(IOError):
+        jupytext(['nb3.ipynb', '--to', 'py'])
+
+
 @pytest.mark.parametrize('nb_file', list_notebooks('ipynb_cpp'))
 def test_to_cpluplus(nb_file, tmpdir, capsys):
     nb_org = str(tmpdir.join(os.path.basename(nb_file)))
@@ -304,15 +324,24 @@ def test_convert_to_percent_format_and_keep_magics(nb_file, tmpdir):
     compare_notebooks(nb1, nb2)
 
 
+def git_in_tmpdir(tmpdir):
+    """Return a function that will execute git instruction in the desired directory"""
+
+    def git(*args):
+        out = system('git', *args, cwd=str(tmpdir))
+        print(out)
+        return out
+
+    return git
+
+
 @skip_if_dict_is_not_ordered
 def test_pre_commit_hook(tmpdir):
     tmp_ipynb = str(tmpdir.join('nb with spaces.ipynb'))
     tmp_py = str(tmpdir.join('nb with spaces.py'))
     nb = new_notebook(cells=[])
 
-    def git(*args):
-        print(system('git', *args, cwd=str(tmpdir)))
-
+    git = git_in_tmpdir(tmpdir)
     git('init')
     git('status')
     hook = str(tmpdir.join('.git/hooks/pre-commit'))
@@ -332,6 +361,37 @@ def test_pre_commit_hook(tmpdir):
     git('commit', '-m', 'created')
     git('status')
 
+    assert 'nb with spaces.py' in git('ls-tree', '-r', 'master', '--name-only')
+    assert os.path.isfile(tmp_py)
+
+
+@skip_if_dict_is_not_ordered
+def test_pre_commit_hook_in_subfolder(tmpdir):
+    tmp_ipynb = str(tmpdir.join('nb with spaces.ipynb'))
+    tmp_py = str(tmpdir.join('python', 'nb with spaces.py'))
+    nb = new_notebook(cells=[])
+
+    git = git_in_tmpdir(tmpdir)
+    git('init')
+    git('status')
+    hook = str(tmpdir.join('.git/hooks/pre-commit'))
+    with open(hook, 'w') as fp:
+        fp.write('#!/bin/sh\n'
+                 'jupytext --from ipynb --to python//py:light --pre-commit\n')
+
+    st = os.stat(hook)
+    os.chmod(hook, st.st_mode | stat.S_IEXEC)
+
+    writef(nb, tmp_ipynb)
+    assert os.path.isfile(tmp_ipynb)
+    assert not os.path.isfile(tmp_py)
+
+    git('add', 'nb with spaces.ipynb')
+    git('status')
+    git('commit', '-m', 'created')
+    git('status')
+
+    assert 'nb with spaces.py' in git('ls-tree', '-r', 'master', '--name-only')
     assert os.path.isfile(tmp_py)
 
 
@@ -342,9 +402,7 @@ def test_pre_commit_hook_py_to_ipynb_and_md(tmpdir):
     tmp_md = str(tmpdir.join('nb with spaces.md'))
     nb = new_notebook(cells=[])
 
-    def git(*args):
-        print(system('git', *args, cwd=str(tmpdir)))
-
+    git = git_in_tmpdir(tmpdir)
     git('init')
     git('status')
     hook = str(tmpdir.join('.git/hooks/pre-commit'))
@@ -366,6 +424,9 @@ def test_pre_commit_hook_py_to_ipynb_and_md(tmpdir):
     git('commit', '-m', 'created')
     git('status')
 
+    assert 'nb with spaces.ipynb' in git('ls-tree', '-r', 'master', '--name-only')
+    assert 'nb with spaces.md' in git('ls-tree', '-r', 'master', '--name-only')
+
     assert os.path.isfile(tmp_ipynb)
     assert os.path.isfile(tmp_md)
 
@@ -377,9 +438,7 @@ def test_pre_commit_hook_sync_black_flake8(tmpdir, nb_file):
     # Load real notebook metadata to get the 'auto' extension in --pipe-fmt to work
     metadata = readf(nb_file).metadata
 
-    def git(*args):
-        print(system('git', *args, cwd=str(tmpdir)))
-
+    git = git_in_tmpdir(tmpdir)
     git('init')
     git('status')
     hook = str(tmpdir.join('.git/hooks/pre-commit'))
@@ -424,9 +483,7 @@ def test_manual_call_of_pre_commit_hook(tmpdir):
     def system_in_tmpdir(*args):
         return system(*args, cwd=str(tmpdir))
 
-    def git(*args):
-        print(system_in_tmpdir('git', *args))
-
+    git = git_in_tmpdir(tmpdir)
     git('init')
     git('status')
 
@@ -444,6 +501,7 @@ def test_manual_call_of_pre_commit_hook(tmpdir):
     git('commit', '-m', 'created')
     git('status')
 
+    assert 'notebook.py' in git('ls-tree', '-r', 'master', '--name-only')
     assert os.path.isfile(tmp_py)
 
 
diff --git a/tests/test_trust_notebook.py b/tests/test_trust_notebook.py
index 984ca4bb..f8b1bc63 100644
--- a/tests/test_trust_notebook.py
+++ b/tests/test_trust_notebook.py
@@ -51,7 +51,7 @@ def test_ipynb_notebooks_can_be_trusted(nb_file, tmpdir):
 
         model = cm.get(file)
         for cell in model['content'].cells:
-            assert 'trusted' not in cell.metadata or not cell.metadata['trusted']
+            assert 'trusted' not in cell.metadata or not cell.metadata['trusted'] or not cell.outputs
 
         # Trust and reload
         cm.trust_notebook(py_file)