Skip to content

Commit

Permalink
Preserve executable and encoding information in scripts with metadata
Browse files Browse the repository at this point in the history
Fixes #241
  • Loading branch information
mwouts committed Jun 5, 2019
1 parent a8c44fa commit 2387c07
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 17 deletions.
2 changes: 1 addition & 1 deletion HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Release History
- Invalid notebooks may cause a warning, but not a fatal error (#234)
- Jupyter server extension leaves the contents manager unchanged if it is a sub-class of Jupytext's CM (#236)
- Fixed format inference when metadata is present but not format information (#239)

- Preserve executable and encoding information in scripts with metadata (#241)

1.1.3 (2019-05-22)
++++++++++++++++++++++
Expand Down
16 changes: 1 addition & 15 deletions jupytext/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from .jupytext import readf, reads, writef, writes
from .formats import _VALID_FORMAT_OPTIONS, _BINARY_FORMAT_OPTIONS, check_file_version
from .formats import long_form_one_format, long_form_multiple_formats, short_form_one_format, auto_ext_from_metadata
from .header import recursive_update
from .paired_paths import paired_paths, base_path, full_path, InconsistentPath
from .combine import combine_inputs_with_outputs
from .compare import test_round_trip_conversion, NotebookDifference
Expand Down Expand Up @@ -404,21 +405,6 @@ def print_paired_paths(nb_file, fmt):
sys.stdout.write(path + '\n')


def recursive_update(target, update):
""" Update recursively a (nested) dictionary with the content of another.
Inspired from https://stackoverflow.com/questions/3232943/update-value-of-a-nested-dictionary-of-varying-depth
"""
for key in update:
value = update[key]
if value is None:
del target[key]
elif isinstance(value, dict):
target[key] = recursive_update(target.get(key, {}), value)
else:
target[key] = value
return target


def set_format_options(fmt, format_options):
"""Apply the desired format options to the format description fmt"""
if not format_options:
Expand Down
17 changes: 16 additions & 1 deletion jupytext/header.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,21 @@ def metadata_and_cell_to_header(notebook, metadata, text_format, ext):
return comment_lines(header, text_format.header_prefix), lines_to_next_cell


def recursive_update(target, update):
""" Update recursively a (nested) dictionary with the content of another.
Inspired from https://stackoverflow.com/questions/3232943/update-value-of-a-nested-dictionary-of-varying-depth
"""
for key in update:
value = update[key]
if value is None:
del target[key]
elif isinstance(value, dict):
target[key] = recursive_update(target.get(key, {}), value)
else:
target[key] = value
return target


def header_to_metadata_and_cell(lines, header_prefix, ext=None):
"""
Return the metadata, a boolean to indicate if a jupyter section was found,
Expand Down Expand Up @@ -177,7 +192,7 @@ def header_to_metadata_and_cell(lines, header_prefix, ext=None):

if ended:
if jupyter:
metadata.update(yaml.safe_load('\n'.join(jupyter))['jupyter'])
recursive_update(metadata, yaml.safe_load('\n'.join(jupyter))['jupyter'])

lines_to_next_cell = 1
if len(lines) > i + 1:
Expand Down
32 changes: 32 additions & 0 deletions tests/test_read_simple_python.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,38 @@ def test_read_write_script(pynb="""#!/usr/bin/env python
compare(pynb, pynb2)


def test_read_write_script_with_metadata_241(pynb="""#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ---
# jupyter:
# jupytext:
# text_representation:
# extension: .py
# format_name: light
# format_version: '1.4'
# jupytext_version: 1.1.2
# kernelspec:
# display_name: Python 3
# language: python
# name: python3
# ---
a = 2
a + 1
"""):
nb = jupytext.reads(pynb, 'py')
assert 'executable' in nb.metadata['jupytext']
assert 'encoding' in nb.metadata['jupytext']
pynb2 = jupytext.writes(nb, 'py')

# remove version information
def remove_version_info(text):
return '\n'.join([line for line in text.splitlines() if 'version' not in line])

compare(remove_version_info(pynb), remove_version_info(pynb2))


def test_notebook_blank_lines(script="""# +
# This is a comment
# followed by two variables
Expand Down

0 comments on commit 2387c07

Please sign in to comment.