Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hide notebook metadata #581

Merged
merged 1 commit into from
Jul 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

**Added**
- Activated GitHub code scanning alerts
- New option `hide_notebook_metadata` to encapsulate the notebook metadata in an HTML comment (#527)

**Changed**
- Install Jupytext from source on MyBinder to avoid cache issues (#567)
Expand Down
2 changes: 2 additions & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ It is possible to filter nested metadata. For example, if you want to preserve t
default_notebook_metadata_filter = "-jupytext.text_representation.jupytext_version"
```

Finally, to hide the notebook metadata in an HTML comment in Markdown files, use the option `hide_notebook_metadata`.

### More options

There are a couple more options available - please have a look at the `JupytextConfiguration` class in [config.py](https://github.com/mwouts/jupytext/blob/master/jupytext/config.py).
24 changes: 11 additions & 13 deletions jupytext/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,9 +409,14 @@ def jupytext_single_file(nb_file, args, log):

# I. ### Read the notebook ###
fmt = copy(args.input_format) or {}
if config:
config.set_default_format_options(fmt)
set_format_options(fmt, args.format_options)
if not fmt:
ext = os.path.splitext(nb_file)[1]
if ext:
fmt = {"extension": ext}
if fmt:
if config:
config.set_default_format_options(fmt)
set_format_options(fmt, args.format_options)
log(
"[jupytext] Reading {}{}".format(
nb_file if nb_file != "-" else "stdin",
Expand All @@ -422,19 +427,12 @@ def jupytext_single_file(nb_file, args, log):
)

notebook = read(nb_file, fmt=fmt)
if not fmt:
if "extension" in fmt and "format_name" not in fmt:
text_representation = notebook.metadata.get("jupytext", {}).get(
"text_representation", {}
)
ext = os.path.splitext(nb_file)[1]
if text_representation.get("extension") == ext:
fmt = {
key: text_representation[key]
for key in text_representation
if key in ["extension", "format_name"]
}
elif ext:
fmt = {"extension": ext}
if text_representation.get("extension") == fmt["extension"]:
fmt["format_name"] = text_representation["format_name"]

if config and "formats" not in notebook.metadata.get("jupytext", {}):
default_formats = config.default_formats(nb_file)
Expand Down
15 changes: 13 additions & 2 deletions jupytext/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,21 @@ class JupytextConfiguration(Configurable):

default_notebook_metadata_filter = Unicode(
u"",
help="Cell metadata that should be save in the text representations. "
help="Notebook metadata that should be save in the text representations. "
"Examples: 'all', '-all', 'widgets,nteract', 'kernelspec,jupytext-all'",
config=True,
)

hide_notebook_metadata = Enum(
values=[True, False],
allow_none=True,
help="Should the notebook metadata be wrapped into an HTML comment in the Markdown format?",
config=True,
)

default_cell_metadata_filter = Unicode(
u"",
help="Notebook metadata that should be saved in the text representations. "
help="Cell metadata that should be saved in the text representations. "
"Examples: 'all', 'hide_input,hide_output'",
config=True,
)
Expand Down Expand Up @@ -124,6 +131,10 @@ def set_default_format_options(self, format_options, read=False):
format_options.setdefault(
"cell_metadata_filter", self.default_cell_metadata_filter
)
if self.hide_notebook_metadata is not None:
format_options.setdefault(
"hide_notebook_metadata", self.hide_notebook_metadata
)
if self.comment_magics is not None:
format_options.setdefault("comment_magics", self.comment_magics)
if self.split_at_heading:
Expand Down
1 change: 1 addition & 0 deletions jupytext/formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,7 @@ def short_form_multiple_formats(jupytext_formats):
_VALID_FORMAT_INFO = ["extension", "format_name", "suffix", "prefix"]
_BINARY_FORMAT_OPTIONS = [
"comment_magics",
"hide_notebook_metadata",
"split_at_heading",
"rst2md",
"cell_metadata_json",
Expand Down
47 changes: 33 additions & 14 deletions jupytext/header.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ def metadata_and_cell_to_header(notebook, metadata, text_format, ext):
if header:
header = ["---"] + header + ["---"]

if (
metadata.get("jupytext", {}).get("hide_notebook_metadata", False)
and text_format.format_name == "markdown"
):
header = ["<!--", ""] + header + ["", "-->"]

return comment_lines(header, text_format.header_prefix), lines_to_next_cell


Expand All @@ -142,10 +148,13 @@ def header_to_metadata_and_cell(lines, header_prefix, ext=None):

header = []
jupyter = []
injupyter = False
in_jupyter = False
in_html_div = False

start = 0
started = False
ended = False
metadata = {}
start = 0
i = -1

comment = "#" if header_prefix == "#'" else header_prefix
Expand All @@ -167,27 +176,37 @@ def header_to_metadata_and_cell(lines, header_prefix, ext=None):
metadata.setdefault("jupytext", {})["encoding"] = line
start = i + 1
continue

if not line.startswith(header_prefix):
break
if not comment:
if line.strip().startswith("<!--"):
in_html_div = True
continue

line = uncomment_line(line, header_prefix)

if i == start:
if _HEADER_RE.match(line):
if in_html_div:
if ended:
if "-->" in line:
break
if not started and not line.strip():
continue
break

if i > start and _HEADER_RE.match(line):
ended = True
break
line = uncomment_line(line, header_prefix)
if _HEADER_RE.match(line):
if not started:
started = True
continue
else:
ended = True
if in_html_div:
continue
break

if _JUPYTER_RE.match(line):
injupyter = True
in_jupyter = True
elif line and not _LEFTSPACE_RE.match(line):
injupyter = False
in_jupyter = False

if injupyter:
if in_jupyter:
jupyter.append(line)
else:
header.append(line)
Expand Down
36 changes: 36 additions & 0 deletions tests/test_cli_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from jupytext.cli import jupytext
from jupytext.jupytext import read, write
from jupytext.header import header_to_metadata_and_cell
from jupytext.compare import compare


def test_default_jupytext_formats(tmpdir):
Expand Down Expand Up @@ -89,3 +90,38 @@ def test_save_using_preferred_and_default_format(config, tmpdir):
# read py file
nb_py = read(str(tmp_py))
assert nb_py.metadata["jupytext"]["text_representation"]["format_name"] == "percent"


def test_hide_notebook_metadata(tmpdir, no_jupytext_version_number):
tmpdir.join(".jupytext").write("hide_notebook_metadata = true")
tmp_ipynb = tmpdir.join("notebook.ipynb")
tmp_md = tmpdir.join("notebook.md")

nb = new_notebook(
cells=[new_code_cell("1 + 1")], metadata={"jupytext": {"formats": "ipynb,md"}}
)

write(nb, str(tmp_ipynb))
jupytext([str(tmp_ipynb), "--sync"])

with open(str(tmp_md)) as stream:
text_md = stream.read()

compare(
text_md,
"""<!--

---
jupyter:
jupytext:
formats: ipynb,md
hide_notebook_metadata: true
---

-->

```python
1 + 1
```
""",
)
38 changes: 38 additions & 0 deletions tests/test_header.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,41 @@ def test_multiline_metadata(
compare(actual, markdown)
nb2 = jupytext.reads(markdown, ".md")
compare(nb2, notebook)


def test_header_in_html_comment():
text = """<!--

---
jupyter:
title: Sample header
---

-->
"""
lines = text.splitlines()
metadata, _, cell, _ = header_to_metadata_and_cell(lines, "")

assert metadata == {"title": "Sample header"}
assert cell is None


def test_header_to_html_comment(no_jupytext_version_number):
metadata = {"jupytext": {"mainlanguage": "python", "hide_notebook_metadata": True}}
nb = new_notebook(metadata=metadata, cells=[])
header, lines_to_next_cell = metadata_and_cell_to_header(
nb, metadata, get_format_implementation(".md"), ".md"
)
compare(
"\n".join(header),
"""<!--

---
jupyter:
jupytext:
hide_notebook_metadata: true
mainlanguage: python
---

-->""",
)
34 changes: 34 additions & 0 deletions tests/test_read_simple_markdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -916,3 +916,37 @@ def test_custom_metadata(
compare(md2, md)
nb2 = jupytext.reads(md, "md")
compare_notebooks(nb2, nb)


def test_hide_notebook_metadata(
no_jupytext_version_number,
nb=new_notebook(
metadata={
"jupytext": {"hide_notebook_metadata": True},
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3",
},
}
),
md="""<!--

---
jupyter:
jupytext:
hide_notebook_metadata: true
kernelspec:
display_name: Python 3
language: python
name: python3
---

-->
""",
):
"""Test the hide_notebook_metadata option"""
md2 = jupytext.writes(nb, "md")
compare(md2, md)
nb2 = jupytext.reads(md, "md")
compare_notebooks(nb2, nb)