Skip to content

Commit

Permalink
The model timestamp of a paired notebook is the timestamp of the inpu…
Browse files Browse the repository at this point in the history
…t file (#983)

* Model timestamp is independent of content=True/False

* Add issue links

* Version 1.14.1

* Update changelog date
  • Loading branch information
mwouts authored Jul 29, 2022
1 parent 5d287b1 commit 12964ef
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 23 deletions.
10 changes: 9 additions & 1 deletion docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
Jupytext ChangeLog
==================

1.14.1 (2022-07-29)
-------------------

**Fixed**
- The timestamp of a paired notebook is the timestamp of the most recent paired file. This fixes the warning "File Changed"
after reloading the notebook in Jupyter ([#978](https://github.com/mwouts/jupytext/issues/978)).


1.14.0 (2022-07-03)
-------------------

Expand All @@ -16,7 +24,7 @@ override existing paired files anymore ([#969](https://github.com/mwouts/jupytex

**Added**
- We have added a test `test_pre_commit_hook_sync_with_no_config` that documents how to use the pre-commit hook without
a configuration file (#967)
a configuration file ([#967](https://github.com/mwouts/jupytext/issues/967))

1.13.8 (2022-04-04)
-------------------
Expand Down
40 changes: 19 additions & 21 deletions jupytext/contentsmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,29 +232,21 @@ def get(
if not load_alternative_format:
return model

if not content:
# Modification time of a paired notebook, in this context - Jupyter is checking timestamp
# before saving - is the most recent among all representations #118
# We will now read a second file if this is a paired notebooks.
if content:
nbk = model["content"]
formats = nbk.metadata.get("jupytext", {}).get(
"formats"
) or config.default_formats(path)
formats = long_form_multiple_formats(
formats, nbk.metadata, auto_ext_requires_language_info=False
)
else:
if path not in self.paired_notebooks:
return model

fmt, formats = self.paired_notebooks.get(path)
for alt_path, _ in paired_paths(path, fmt, formats):
if alt_path != path and self.exists(alt_path):
alt_model = self.super.get(alt_path, content=False)
if alt_model["last_modified"] > model["last_modified"]:
model["last_modified"] = alt_model["last_modified"]

return model

# We will now read a second file if this is a paired notebooks.
nbk = model["content"]
formats = nbk.metadata.get("jupytext", {}).get(
"formats"
) or config.default_formats(path)
formats = long_form_multiple_formats(
formats, nbk.metadata, auto_ext_requires_language_info=False
)
_, formats = self.paired_notebooks.get(path)
formats = long_form_multiple_formats(formats)

# Compute paired notebooks from formats
alt_paths = [(path, fmt)]
Expand All @@ -276,7 +268,7 @@ def get(
alt_paths = paired_paths(path, fmt, formats)
formats = long_form_multiple_formats(formats)

if len(alt_paths) > 1 and ext == ".ipynb":
if content and len(alt_paths) > 1 and ext == ".ipynb":
# Apply default options (like saving and reloading would do)
jupytext_metadata = model["content"]["metadata"].get("jupytext", {})
config.set_default_format_options(jupytext_metadata, read=True)
Expand Down Expand Up @@ -309,6 +301,12 @@ def read_one_file(alt_path, alt_fmt):
path, fmt, formats, get_timestamp, contents_manager_mode=True
)

# Modification time of a paired notebook is the timestamp of inputs #118 #978
model["last_modified"] = inputs.timestamp

if not content:
return model

# Before we combine the two files, we make sure we're not overwriting ipynb cells
# with an outdated text file
content = None
Expand Down
2 changes: 1 addition & 1 deletion jupytext/version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Jupytext's version number"""

__version__ = "1.14.0"
__version__ = "1.14.1"
42 changes: 42 additions & 0 deletions tests/test_contentsmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1949,3 +1949,45 @@ def test_config_jupytext_jupyter_fs_meta_manager(tmpdir):
"script.py",
"script.ipynb",
}


def test_timestamp_is_correct_after_reload_978(tmp_path, python_notebook):
"""Here we reproduce the conditions in Issue #978 and make sure no
warning is generated"""
nb = python_notebook
nb.metadata["jupytext"] = {"formats": "ipynb,py:percent"}

cm = jupytext.TextFileContentsManager()
cm.root_dir = str(tmp_path)

ipynb_file = tmp_path / "nb.ipynb"
py_file = tmp_path / "nb.py"

# 1. Save the paired notebook
cm.save(notebook_model(nb), path="nb.ipynb")
assert ipynb_file.exists()
assert py_file.exists()

# and reload to get the original timestamp
org_model = cm.get("nb.ipynb")

# 2. Edit the py file
time.sleep(0.5)
text = py_file.read_text()
text = (
text
+ """
# %%
# A new cell
2 + 2
"""
)

py_file.write_text(text)

# 3. Reload the paired notebook and make sure it has the modified content
model = cm.get("nb.ipynb")
nb = model["content"]
assert "A new cell" in nb.cells[-1].source
assert model["last_modified"] > org_model["last_modified"]

0 comments on commit 12964ef

Please sign in to comment.