From 953ce379136b00fead094d128c14d427300587f9 Mon Sep 17 00:00:00 2001 From: Marc Wouts Date: Sat, 2 Nov 2019 23:49:32 +0100 Subject: [PATCH] Multiple pairing in Jupytext's contents manager #290 --- HISTORY.rst | 1 + jupytext/contentsmanager.py | 22 ++++++++++++-------- tests/test_contentsmanager.py | 38 +++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 04c4a5eb1..1a671da22 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -8,6 +8,7 @@ Release History **Improvements** +- Pairing a notebook to both `.md` and `.py` is now supported in Jupyter. Input cells are loaded from the most recent text representation. (#290). - Raw cells are now encoded using HTML comments (```` and ````) in Markdown files (#321) - Markdown cells can be delimited with any of ````, ```` or ```` (#344) - Code blocks from Markdown files, when they don't have an explicit language, appear in Markdown cells in Jupyter (#321) diff --git a/jupytext/contentsmanager.py b/jupytext/contentsmanager.py index add9266ac..2aa0d0428 100644 --- a/jupytext/contentsmanager.py +++ b/jupytext/contentsmanager.py @@ -350,17 +350,23 @@ def get(self, path, content=True, type=None, format=None, load_alternative_forma path_inputs = path_outputs = path model_outputs = None - # Source format is first non ipynb format found on disk + # Source format is the most recent non ipynb format found on disk if path.endswith('.ipynb'): + most_recent_timestamp = None for alt_path, alt_fmt in alt_paths: if not alt_path.endswith('.ipynb') and self.exists(alt_path): - self.log.info(u'Reading SOURCE from {}'.format(alt_path)) - path_inputs = alt_path - fmt_inputs = alt_fmt - model_outputs = model - model = self.get(alt_path, content=content, type='notebook', format=format, - load_alternative_format=False) - break + alt_model = self._notebook_model(alt_path, content=False) + if most_recent_timestamp is None or alt_model['last_modified'] > most_recent_timestamp: + most_recent_timestamp = alt_model['last_modified'] + model_outputs = model + path_inputs = alt_path + fmt_inputs = alt_fmt + + if most_recent_timestamp is not None: + self.log.info(u'Reading SOURCE from {}'.format(path_inputs)) + model = self.get(path_inputs, content=content, type='notebook', format=format, + load_alternative_format=False) + # Outputs taken from ipynb if in group, if file exists else: for alt_path, _ in alt_paths: diff --git a/tests/test_contentsmanager.py b/tests/test_contentsmanager.py index 388904499..728f10102 100644 --- a/tests/test_contentsmanager.py +++ b/tests/test_contentsmanager.py @@ -1543,3 +1543,41 @@ class SubClassTextFileContentsManager(jupytext.TextFileContentsManager): assert not isinstance(SubClassTextFileContentsManager, jupytext.TextFileContentsManager) assert issubclass(SubClassTextFileContentsManager, jupytext.TextFileContentsManager) + + +def test_multiple_pairing(tmpdir): + """Test that multiple pairing works. Input cells are loaded from the most recent text representation among + the paired ones""" + tmp_ipynb = str(tmpdir.join('notebook.ipynb')) + tmp_md = str(tmpdir.join('notebook.md')) + tmp_py = str(tmpdir.join('notebook.py')) + + def nb(text): + return new_notebook(cells=[new_markdown_cell(text)], + metadata={'jupytext': {'formats': 'ipynb,md,py'}}) + + cm = jupytext.TextFileContentsManager() + cm.root_dir = str(tmpdir) + + cm.save(model=dict(type='notebook', content=nb('saved from cm')), path='notebook.ipynb') + compare_notebooks(jupytext.read(tmp_ipynb), nb('saved from cm')) + compare_notebooks(jupytext.read(tmp_md), nb('saved from cm')) + compare_notebooks(jupytext.read(tmp_py), nb('saved from cm')) + + jupytext.write(nb('md edited'), tmp_md) + model = cm.get('notebook.ipynb') + compare_notebooks(model['content'], nb('md edited')) + + cm.save(model=model, path='notebook.ipynb') + compare_notebooks(jupytext.read(tmp_ipynb), nb('md edited')) + compare_notebooks(jupytext.read(tmp_md), nb('md edited')) + compare_notebooks(jupytext.read(tmp_py), nb('md edited')) + + jupytext.write(nb('py edited'), tmp_py) + model = cm.get('notebook.ipynb') + compare_notebooks(model['content'], nb('py edited')) + + cm.save(model=model, path='notebook.ipynb') + compare_notebooks(jupytext.read(tmp_ipynb), nb('py edited')) + compare_notebooks(jupytext.read(tmp_md), nb('py edited')) + compare_notebooks(jupytext.read(tmp_py), nb('py edited'))