def test_load_save_rename_non_ascii_path(nb_file, tmpdir): tmp_ipynb = u'notebôk.ipynb' tmp_nbpy = u'notebôk.nb.py' cm = jupytext.TextFileContentsManager() cm.default_jupytext_formats = 'ipynb' tmpdir = u'' + str(tmpdir) cm.root_dir = tmpdir # open ipynb, save nb.py, reopen nb = jupytext.readf(nb_file) if nb.metadata.get('jupytext', {}).get('formats'): del nb.metadata['jupytext']['formats'] cm.save(model=dict(type='notebook', content=nb), path=tmp_nbpy) nbpy = cm.get(tmp_nbpy) compare_notebooks(nb, nbpy['content']) # open ipynb nbipynb = cm.get(tmp_ipynb) compare_notebooks(nb, nbipynb['content']) # save ipynb cm.save(model=dict(type='notebook', content=nb), path=tmp_ipynb) # rename nbpy cm.rename(tmp_nbpy, u'nêw.nb.py') assert not os.path.isfile(os.path.join(tmpdir, tmp_ipynb)) assert not os.path.isfile(os.path.join(tmpdir, tmp_nbpy)) assert os.path.isfile(os.path.join(tmpdir, u'nêw.ipynb')) assert os.path.isfile(os.path.join(tmpdir, u'nêw.nb.py')) # rename ipynb cm.rename(u'nêw.ipynb', tmp_ipynb) assert os.path.isfile(os.path.join(tmpdir, tmp_ipynb)) assert not os.path.isfile(os.path.join(tmpdir, tmp_nbpy)) assert not os.path.isfile(os.path.join(tmpdir, u'nêw.ipynb')) assert os.path.isfile(os.path.join(tmpdir, u'nêw.nb.py'))
def test_load_save_rename(nb_file, tmpdir): tmp_ipynb = 'notebook.ipynb' tmp_rmd = 'notebook.Rmd' cm = jupytext.TextFileContentsManager() cm.default_jupytext_formats = 'ipynb,Rmd' cm.root_dir = str(tmpdir) # open ipynb, save Rmd, reopen nb = jupytext.readf(nb_file) cm.save(model=dict(type='notebook', content=nb), path=tmp_rmd) nb_rmd = cm.get(tmp_rmd) compare_notebooks(nb, nb_rmd['content'], 'Rmd') # save ipynb cm.save(model=dict(type='notebook', content=nb), path=tmp_ipynb) # rename ipynb cm.rename(tmp_ipynb, 'new.ipynb') assert not os.path.isfile(str(tmpdir.join(tmp_ipynb))) assert not os.path.isfile(str(tmpdir.join(tmp_rmd))) assert os.path.isfile(str(tmpdir.join('new.ipynb'))) assert os.path.isfile(str(tmpdir.join('new.Rmd'))) # delete one file, test that we can still read and rename it cm.delete('new.Rmd') assert not os.path.isfile(str(tmpdir.join('new.Rmd'))) model = cm.get('new.ipynb', content=False) assert 'last_modified' in model cm.save(model=dict(type='notebook', content=nb), path='new.ipynb') assert os.path.isfile(str(tmpdir.join('new.Rmd'))) cm.delete('new.Rmd') cm.rename('new.ipynb', tmp_ipynb) assert os.path.isfile(str(tmpdir.join(tmp_ipynb))) assert not os.path.isfile(str(tmpdir.join(tmp_rmd))) assert not os.path.isfile(str(tmpdir.join('new.ipynb'))) assert not os.path.isfile(str(tmpdir.join('new.Rmd')))
def test_default_cell_markers_in_contents_manager_does_not_impact_light_format( tmpdir): tmp_ipynb = str(tmpdir.join("notebook.ipynb")) tmp_py = str(tmpdir.join("notebook.py")) cm = jupytext.TextFileContentsManager() cm.root_dir = str(tmpdir) cm.default_cell_markers = "'''" nb = new_notebook( cells=[new_code_cell("1 + 1"), new_markdown_cell("a\nlong\ncell")], metadata={ "jupytext": { "formats": "ipynb,py", "notebook_metadata_filter": "-all" } }, ) with pytest.warns(UserWarning, match="Ignored cell markers"): cm.save(model=notebook_model(nb), path="notebook.ipynb") assert os.path.isfile(tmp_ipynb) assert os.path.isfile(tmp_py) with open(tmp_py) as fp: text = fp.read() compare( text, """1 + 1 # a # long # cell """, ) nb2 = jupytext.read(tmp_py) compare_notebooks(nb, nb2)
def test_notebook_extensions(tmpdir): tmp_py = str(tmpdir.join('script.py')) tmp_rmd = str(tmpdir.join('notebook.Rmd')) tmp_ipynb = str(tmpdir.join('notebook.ipynb')) nb = new_notebook() writef(nb, tmp_py) writef(nb, tmp_rmd) writef(nb, tmp_ipynb) cm = jupytext.TextFileContentsManager() cm.root_dir = str(tmpdir) cm.notebook_extensions = 'ipynb,Rmd' model = cm.get('notebook.ipynb') assert model['type'] == 'notebook' model = cm.get('notebook.Rmd') assert model['type'] == 'notebook' model = cm.get('script.py') assert model['type'] == 'file'
def test_metadata_filter_is_effective(nb_file, tmpdir): nb = jupytext.readf(nb_file) tmp_ipynb = 'notebook.ipynb' tmp_script = 'notebook.py' # create contents manager cm = jupytext.TextFileContentsManager() cm.root_dir = str(tmpdir) # save notebook to tmpdir cm.save(model=dict(type='notebook', content=nb), path=tmp_ipynb) # set config cm.default_jupytext_formats = 'ipynb,py' cm.default_notebook_metadata_filter = 'jupytext,-all' cm.default_cell_metadata_filter = '-all' # load notebook nb = cm.get(tmp_ipynb)['content'] assert nb.metadata['jupytext']['cell_metadata_filter'] == '-all' assert nb.metadata['jupytext'][ 'notebook_metadata_filter'] == 'jupytext,-all' # save notebook again cm.save(model=dict(type='notebook', content=nb), path=tmp_ipynb) # read text version nb2 = jupytext.readf(str(tmpdir.join(tmp_script))) # test no metadata assert set(nb2.metadata.keys()) <= {'jupytext'} for cell in nb2.cells: assert not cell.metadata # read paired notebook nb3 = cm.get(tmp_script)['content'] compare_notebooks(nb, nb3)
def test_python_kernel_preserves_R_files(nb_file, tmpdir): """Opening a R file with a Jupyter server that has no R kernel should not modify the file""" tmp_r_file = str(tmpdir.join('script.R')) with open(nb_file) as fp: script = fp.read() with open(tmp_r_file, 'w') as fp: fp.write(script) # create contents manager cm = jupytext.TextFileContentsManager() cm.root_dir = str(tmpdir) # open notebook, set Python kernel and save model = cm.get('script.R') model['content'].metadata['kernelspec'] = kernelspec_from_language( 'python') cm.save(model=model, path='script.R') with open(tmp_r_file) as fp: script2 = fp.read() compare(script, script2)
def test_save_to_percent_format(nb_file, tmpdir): tmp_ipynb = 'notebook.ipynb' tmp_jl = 'notebook.jl' cm = jupytext.TextFileContentsManager() cm.root_dir = str(tmpdir) cm.preferred_jupytext_formats_save = 'jl:percent' nb = jupytext.readf(nb_file) nb['metadata']['jupytext'] = {'formats': 'ipynb,jl'} # save to ipynb and jl with mock.patch('jupytext.header.INSERT_AND_CHECK_VERSION_NUMBER', True): cm.save(model=dict(type='notebook', content=nb), path=tmp_ipynb) # read jl file with open(str(tmpdir.join(tmp_jl))) as stream: text_jl = stream.read() # Parse the YAML header metadata, _, _ = header_to_metadata_and_cell(text_jl.splitlines(), '#') assert metadata['jupytext']['formats'] == 'ipynb,jl:percent'
def test_load_save_py_freeze_metadata(script, tmpdir): tmp_nbpy = 'notebook.py' cm = jupytext.TextFileContentsManager() cm.root_dir = str(tmpdir) # read original file with open(script) as fp: text_py = fp.read() # write to tmp_nbpy with open(str(tmpdir.join(tmp_nbpy)), 'w') as fp: fp.write(text_py) # open and save notebook nb = cm.get(tmp_nbpy)['content'] cm.save(model=dict(type='notebook', content=nb), path=tmp_nbpy) with open(str(tmpdir.join(tmp_nbpy))) as fp: text_py2 = fp.read() compare(text_py, text_py2)
def test_save_to_light_percent_sphinx_format(nb_file, tmpdir): tmp_ipynb = 'notebook.ipynb' tmp_lgt_py = 'notebook.lgt.py' tmp_pct_py = 'notebook.pct.py' tmp_spx_py = 'notebook.spx.py' cm = jupytext.TextFileContentsManager() cm.root_dir = str(tmpdir) nb = jupytext.readf(nb_file) nb['metadata']['jupytext'] = { 'formats': 'ipynb,.pct.py:percent,.lgt.py:light,.spx.py:sphinx' } # save to ipynb and three python flavors cm.save(model=dict(type='notebook', content=nb), path=tmp_ipynb) # read files with open(str(tmpdir.join(tmp_pct_py))) as stream: assert read_format_from_metadata(stream.read(), '.py') == 'percent' with open(str(tmpdir.join(tmp_lgt_py))) as stream: assert read_format_from_metadata(stream.read(), '.py') == 'light' with open(str(tmpdir.join(tmp_spx_py))) as stream: assert read_format_from_metadata(stream.read(), '.py') == 'sphinx' model = cm.get(path=tmp_pct_py) compare_notebooks(nb, model['content']) model = cm.get(path=tmp_lgt_py) compare_notebooks(nb, model['content']) model = cm.get(path=tmp_spx_py) # (notebooks not equal as we insert %matplotlib inline in sphinx) model = cm.get(path=tmp_ipynb) compare_notebooks(nb, model['content'])
def test_default_cell_markers_in_contents_manager(tmpdir): tmp_ipynb = str(tmpdir.join('notebook.ipynb')) tmp_py = str(tmpdir.join('notebook.py')) cm = jupytext.TextFileContentsManager() cm.root_dir = str(tmpdir) cm.default_cell_markers = "'''" nb = new_notebook( cells=[new_code_cell('1 + 1'), new_markdown_cell('a\nlong\ncell')], metadata={ 'jupytext': { 'formats': 'ipynb,py:percent', 'notebook_metadata_filter': '-all' } }) cm.save(model=dict(type='notebook', content=nb), path='notebook.ipynb') assert os.path.isfile(tmp_ipynb) assert os.path.isfile(tmp_py) with open(tmp_py) as fp: text = fp.read() compare(text, """# %% 1 + 1 # %% [markdown] ''' a long cell ''' """) nb2 = jupytext.read(tmp_py) compare_notebooks(nb, nb2)
def test_global_config_file(tmpdir): cm_dir = tmpdir.join("cm_dir").mkdir() cm = jupytext.TextFileContentsManager() cm.root_dir = str(cm_dir) tmpdir.join("jupytext.toml").write( 'default_jupytext_formats = "ipynb,Rmd"') def fake_global_config_directory(): return [str(tmpdir)] with mock.patch( "jupytext.config.global_jupytext_configuration_directories", fake_global_config_directory, ): nb = new_notebook(cells=[new_code_cell("1+1")]) model = notebook_model(nb) cm.save(model, "notebook.ipynb") assert set(model["path"] for model in cm.get("/", content=True)["content"]) == { "notebook.ipynb", "notebook.Rmd", }
def test_combine_lower_version_raises(tmpdir): tmp_ipynb = "notebook.ipynb" tmp_nbpy = "notebook.py" with open(str(tmpdir.join(tmp_nbpy)), "w") as fp: fp.write("""# --- # jupyter: # jupytext_formats: ipynb,py # jupytext_format_version: '0.0' # --- # New cell """) nb = new_notebook(metadata={"jupytext_formats": "ipynb,py"}) jupytext.write(nb, str(tmpdir.join(tmp_ipynb))) cm = jupytext.TextFileContentsManager() cm.formats = "ipynb,py" cm.root_dir = str(tmpdir) with pytest.raises(HTTPError): cm.get(tmp_ipynb)
def test_combine_lower_version_raises(tmpdir): tmp_ipynb = 'notebook.ipynb' tmp_nbpy = 'notebook.py' with open(str(tmpdir.join(tmp_nbpy)), 'w') as fp: fp.write("""# --- # jupyter: # jupytext_formats: ipynb,py # jupytext_format_version: '0.0' # --- # New cell """) nb = new_notebook(metadata={'jupytext_formats': 'ipynb,py'}) jupytext.write(nb, str(tmpdir.join(tmp_ipynb))) cm = jupytext.TextFileContentsManager() cm.default_jupytext_formats = 'ipynb,py' cm.root_dir = str(tmpdir) with pytest.raises(HTTPError): cm.get(tmp_ipynb)
def test_pair_plain_script(py_file, tmpdir): tmp_py = 'notebook.py' tmp_ipynb = 'notebook.ipynb' cm = jupytext.TextFileContentsManager() cm.root_dir = str(tmpdir) # open py file, pair, save with cm nb = jupytext.readf(py_file) nb.metadata['jupytext']['formats'] = 'ipynb,py:hydrogen' cm.save(model=dict(type='notebook', content=nb), path=tmp_py) assert os.path.isfile(str(tmpdir.join(tmp_py))) assert os.path.isfile(str(tmpdir.join(tmp_ipynb))) # Make sure we've not changed the script with open(py_file) as fp: script = fp.read() with open(str(tmpdir.join(tmp_py))) as fp: script2 = fp.read() compare(script, script2) # reopen py file with the cm nb2 = cm.get(tmp_py)['content'] compare_notebooks(nb, nb2) assert nb2.metadata['jupytext']['formats'] == 'ipynb,py:hydrogen' # remove the pairing and save del nb.metadata['jupytext']['formats'] cm.save(model=dict(type='notebook', content=nb), path=tmp_py) # reopen py file with the cm nb2 = cm.get(tmp_py)['content'] compare_notebooks(nb, nb2) assert 'formats' not in nb2.metadata['jupytext']
def test_outdated_text_notebook(nb_file, tmpdir): # 1. write py ipynb tmp_ipynb = u'notebook.ipynb' tmp_nbpy = u'notebook.py' cm = jupytext.TextFileContentsManager() cm.default_jupytext_formats = 'py,ipynb' cm.outdated_text_notebook_margin = 0 cm.root_dir = str(tmpdir) # open ipynb, save py, reopen nb = jupytext.readf(nb_file) cm.save(model=dict(type='notebook', content=nb), path=tmp_nbpy) model_py = cm.get(tmp_nbpy, load_alternative_format=False) model_ipynb = cm.get(tmp_ipynb, load_alternative_format=False) # 2. check that time of ipynb <= py assert model_ipynb['last_modified'] <= model_py['last_modified'] # 3. wait some time time.sleep(0.5) # 4. touch ipynb with open(str(tmpdir.join(tmp_ipynb)), 'a'): os.utime(str(tmpdir.join(tmp_ipynb)), None) # 5. test error with pytest.raises(HTTPError): cm.get(tmp_nbpy) # 6. test OK with cm.outdated_text_notebook_margin = 1.0 cm.get(tmp_nbpy) # 7. test OK with cm.outdated_text_notebook_margin = float("inf") cm.get(tmp_nbpy)
def test_load_save_rename_nbpy_default_config(nb_file, tmpdir): tmp_ipynb = 'notebook.ipynb' tmp_nbpy = 'notebook.nb.py' cm = jupytext.TextFileContentsManager() cm.default_jupytext_formats = 'ipynb,.nb.py' cm.root_dir = str(tmpdir) # open ipynb, save nb.py, reopen nb = jupytext.readf(nb_file) cm.save(model=dict(type='notebook', content=nb), path=tmp_nbpy) nbpy = cm.get(tmp_nbpy) compare_notebooks(nb, nbpy['content']) # open ipynb nbipynb = cm.get(tmp_ipynb) compare_notebooks(nb, nbipynb['content']) # save ipynb cm.save(model=dict(type='notebook', content=nb), path=tmp_ipynb) # rename notebook.nb.py to new.nb.py cm.rename(tmp_nbpy, 'new.nb.py') assert not os.path.isfile(str(tmpdir.join(tmp_ipynb))) assert not os.path.isfile(str(tmpdir.join(tmp_nbpy))) assert os.path.isfile(str(tmpdir.join('new.ipynb'))) assert os.path.isfile(str(tmpdir.join('new.nb.py'))) # rename new.ipynb to notebook.ipynb cm.rename('new.ipynb', tmp_ipynb) assert os.path.isfile(str(tmpdir.join(tmp_ipynb))) assert os.path.isfile(str(tmpdir.join(tmp_nbpy))) assert not os.path.isfile(str(tmpdir.join('new.ipynb'))) assert not os.path.isfile(str(tmpdir.join('new.nb.py')))
def test_load_save_rename_notebook_with_dot(nb_file, tmpdir): tmp_ipynb = '1.notebook.ipynb' tmp_nbpy = '1.notebook.py' cm = jupytext.TextFileContentsManager() cm.default_jupytext_formats = 'ipynb,py' cm.root_dir = str(tmpdir) # open ipynb, save nb.py, reopen nb = jupytext.read(nb_file) cm.save(model=dict(type='notebook', content=nb), path=tmp_nbpy) nbpy = cm.get(tmp_nbpy) compare_notebooks(nb, nbpy['content']) # save ipynb cm.save(model=dict(type='notebook', content=nb), path=tmp_ipynb) # rename py cm.rename(tmp_nbpy, '2.new_notebook.py') assert not os.path.isfile(str(tmpdir.join(tmp_ipynb))) assert not os.path.isfile(str(tmpdir.join(tmp_nbpy))) assert os.path.isfile(str(tmpdir.join('2.new_notebook.ipynb'))) assert os.path.isfile(str(tmpdir.join('2.new_notebook.py')))
def test_load_save_rename(nb_file, tmpdir): tmp_ipynb = 'notebook.ipynb' tmp_rmd = 'notebook.Rmd' cm = jupytext.TextFileContentsManager() cm.default_jupytext_formats = 'ipynb,Rmd' cm.root_dir = str(tmpdir) # open ipynb, save Rmd, reopen nb = jupytext.readf(nb_file) cm.save(model=dict(type='notebook', content=nb), path=tmp_rmd) nb_rmd = cm.get(tmp_rmd) compare_notebooks(nb, nb_rmd['content']) # save ipynb cm.save(model=dict(type='notebook', content=nb), path=tmp_ipynb) # rename ipynb cm.rename(tmp_ipynb, 'new.ipynb') assert not os.path.isfile(str(tmpdir.join(tmp_ipynb))) assert not os.path.isfile(str(tmpdir.join(tmp_rmd))) assert os.path.isfile(str(tmpdir.join('new.ipynb'))) assert os.path.isfile(str(tmpdir.join('new.Rmd')))
def test_meaningfull_error_open_myst_missing(tmpdir): md_file = tmpdir.join("notebook.md") md_file.write("""--- jupytext: text_representation: extension: '.md' format_name: myst kernelspec: display_name: Python 3 language: python name: python3 --- 1 + 1 """) with pytest.raises(ImportError, match=PLEASE_INSTALL_MYST): jupytext_cli([str(md_file), "--to", "ipynb"]) cm = jupytext.TextFileContentsManager() cm.root_dir = str(tmpdir) with pytest.raises(HTTPError, match=PLEASE_INSTALL_MYST): cm.get("notebook.md")
def test_set_then_change_auto_formats(tmpdir, nb_file): tmp_ipynb = str(tmpdir.join('nb.ipynb')) tmp_py = str(tmpdir.join('nb.py')) tmp_rmd = str(tmpdir.join('nb.Rmd')) nb = new_notebook(metadata=readf(nb_file).metadata) cm = jupytext.TextFileContentsManager() cm.root_dir = str(tmpdir) # Pair ipynb/py and save nb.metadata['jupytext'] = {'formats': 'ipynb,auto:light'} cm.save(model=dict(content=nb, type='notebook'), path='nb.ipynb') assert 'nb.py' in cm.paired_notebooks assert 'nb.auto' not in cm.paired_notebooks assert os.path.isfile(tmp_py) assert readf(tmp_ipynb).metadata['jupytext']['formats'] == 'ipynb,py:light' # Pair ipynb/Rmd and save time.sleep(0.5) nb.metadata['jupytext'] = {'formats': 'ipynb,Rmd'} cm.save(model=dict(content=nb, type='notebook'), path='nb.ipynb') assert 'nb.Rmd' in cm.paired_notebooks assert 'nb.py' not in cm.paired_notebooks assert 'nb.auto' not in cm.paired_notebooks assert os.path.isfile(tmp_rmd) assert readf(tmp_ipynb).metadata['jupytext']['formats'] == 'ipynb,Rmd' cm.get('nb.ipynb') # Unpair and save time.sleep(0.5) del nb.metadata['jupytext'] cm.save(model=dict(content=nb, type='notebook'), path='nb.ipynb') assert 'nb.Rmd' not in cm.paired_notebooks assert 'nb.py' not in cm.paired_notebooks assert 'nb.auto' not in cm.paired_notebooks cm.get('nb.ipynb')
def test_open_file_with_default_cell_markers(tmpdir): tmp_py = str(tmpdir.join('nb.py')) cm = jupytext.TextFileContentsManager() cm.root_dir = str(tmpdir) # Default VScode/PyCharm folding markers cm.default_cell_markers = 'region,endregion' text = """# + # this is a unique code cell 1 + 1 2 + 2 """ with open(tmp_py, 'w') as fp: fp.write(text) nb = cm.get('nb.py')['content'] assert len(nb.cells) == 1 cm.save(model=dict(type='notebook', content=nb), path='nb.py') with open(tmp_py) as fp: text2 = fp.read() expected = """# region # this is a unique code cell 1 + 1 2 + 2 # endregion """ compare(expected, text2)
def test_save_in_auto_extension_local(nb_file, tmpdir): # load notebook nb = jupytext.read(nb_file) nb.metadata.setdefault('jupytext', {})['formats'] = 'ipynb,auto:percent' auto_ext = auto_ext_from_metadata(nb.metadata) tmp_ipynb = 'notebook.ipynb' tmp_script = 'notebook' + auto_ext # create contents manager with default load format as percent cm = jupytext.TextFileContentsManager() cm.root_dir = str(tmpdir) # save notebook cm.save(model=dict(type='notebook', content=nb), path=tmp_ipynb) # check that text representation exists, and is in percent format with open(str(tmpdir.join(tmp_script))) as stream: assert read_format_from_metadata(stream.read(), auto_ext) == 'percent' # reload and compare with original notebook model = cm.get(path=tmp_script) compare_notebooks(nb, model['content'])
def test_read_text_and_combine_with_outputs(tmpdir): tmp_ipynb = 'notebook.ipynb' tmp_script = 'notebook.py' with (open(str(tmpdir.join(tmp_script)), 'w')) as fp: fp.write("""# --- # jupyter: # jupytext_formats: ipynb,py:light # --- 1+1 2+2 3+3 """) with (open(str(tmpdir.join(tmp_ipynb)), 'w')) as fp: fp.write("""{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "1+1" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "3+3" ] } ], "metadata": {}, "nbformat": 4, "nbformat_minor": 2 } """) # create contents manager cm = jupytext.TextFileContentsManager() cm.root_dir = str(tmpdir) # load notebook from script model = cm.get(tmp_script) nb = model['content'] assert nb.cells[0]['source'] == '1+1' assert nb.cells[1]['source'] == '2+2' assert nb.cells[2]['source'] == '3+3' # No output for the second cell, which is not in the ipynb assert nb.cells[0]['outputs'] assert not nb.cells[1]['outputs'] assert nb.cells[2]['outputs'] assert len(nb.cells) == 3
def test_create_contentsmanager(): jupytext.TextFileContentsManager()