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

Quote strings in Rmd chunk options #385

Merged
merged 1 commit into from
Nov 14, 2019
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 @@ -35,6 +35,7 @@
- `jupytext --test textfile.ext` now really compares the text file to its round trip (rather than the corresponding notebook) (#339)
- Markdown cells that contain code are now preserved in a round trip through the Markdown and R Markdown formats (#361)
- Code cells with a `%%python3` cell magic are now preserved in a round trip through the Markdown format (#365)
- Strings in the metadata of code cells are quoted in the Rmd representation. And we escape R code in chunk options with `#R_CODE#` (#383)


1.2.4 (2019-09-19)
Expand Down
14 changes: 11 additions & 3 deletions jupytext/cell_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ def metadata_to_rmd_options(language, metadata, use_runtools=False):
options += ' {}={},'.format(
opt_name, 'c({})'.format(
', '.join(['"{}"'.format(str(v)) for v in opt_value])))
elif isinstance(opt_value, (str, unicode)):
if opt_value.startswith('#R_CODE#'):
options += ' {}={},'.format(opt_name, opt_value[8:])
elif '"' not in opt_value:
options += ' {}="{}",'.format(opt_name, opt_value)
else:
options += " {}='{}',".format(opt_name, opt_value)
else:
options += ' {}={},'.format(opt_name, str(opt_value))
if not language:
Expand Down Expand Up @@ -267,13 +274,12 @@ def metadata_to_md_options(metadata):


def try_eval_metadata(metadata, name):
"""Evaluate given metadata to a python object, if possible"""
"""Evaluate the metadata to a python object, if possible"""
value = metadata[name]
if not isinstance(value, (str, unicode)):
return
if (value.startswith('"') and value.endswith('"')) or (value.startswith("'") and value.endswith("'")):
if name in ['active', 'magic_args', 'language']:
metadata[name] = value[1:-1]
metadata[name] = value[1:-1]
return
if value.startswith('c(') and value.endswith(')'):
value = '[' + value[2:-1] + ']'
Expand All @@ -282,6 +288,8 @@ def try_eval_metadata(metadata, name):
try:
metadata[name] = ast.literal_eval(value)
except (SyntaxError, ValueError):
if name != 'name':
metadata[name] = '#R_CODE#' + value
return


Expand Down
3 changes: 0 additions & 3 deletions jupytext/cell_to_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@ def __init__(self, cell, default_language, fmt=None):

if self.language:
if magic_args:
if self.ext.endswith('.Rmd'):
quote = '"' if "'" in magic_args else "'"
magic_args = quote + magic_args + quote
self.metadata['magic_args'] = magic_args

if not self.ext.endswith('.Rmd'):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@ This is a markdown cell with cell metadata `{"key": "value"}`
"""This is a code cell with metadata `{"tags":["parameters"], ".class":null}`"""
```

```{python key=value, active="", eval=FALSE}
```{python key="value", active="", eval=FALSE}
This is a raw cell with cell metadata `{"key": "value"}`
```
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ ggplot(iris, aes(x = Sepal.Length, y = Petal.Length, color=Species)) + geom_poin

The default plot dimensions are not good for us, so we use the -w and -h parameters in %%R magic to set the plot size

```{r magic_args='-w 400 -h 240'}
```{r magic_args="-w 400 -h 240"}
ggplot(iris, aes(x = Sepal.Length, y = Petal.Length, color=Species)) + geom_point()
```
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ df = pd.DataFrame(
)
```

```{r magic_args='-i df'}
```{r magic_args="-i df"}
library("ggplot2")
ggplot(data = df) + geom_point(aes(x = X, y = Y, color = Letter, size = Z))
```
10 changes: 5 additions & 5 deletions tests/notebooks/mirror/ipynb_to_Rmd/The flavors of raw cells.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@ jupyter:
name: python3
---

```{python raw_mimetype=text/latex, active="", eval=FALSE}
```{python raw_mimetype="text/latex", active="", eval=FALSE}
$1+1$
```

```{python raw_mimetype=text/restructuredtext, active="", eval=FALSE}
```{python raw_mimetype="text/restructuredtext", active="", eval=FALSE}
:math:`1+1`
```

```{python raw_mimetype=text/html, active="", eval=FALSE}
```{python raw_mimetype="text/html", active="", eval=FALSE}
<b>Bold text<b>
```

```{python raw_mimetype=text/markdown, active="", eval=FALSE}
```{python raw_mimetype="text/markdown", active="", eval=FALSE}
**Bold text**
```

```{python raw_mimetype=text/x-python, active="", eval=FALSE}
```{python raw_mimetype="text/x-python", active="", eval=FALSE}
1 + 1
```

Expand Down
10 changes: 5 additions & 5 deletions tests/test_cell_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@

SAMPLES = [('r', ('R', {})),
('r plot_1, dpi=72, fig.path="fig_path/"',
('R', {'name': 'plot_1', 'dpi': 72, 'fig.path': '"fig_path/"'})),
("r plot_1, bool=TRUE, fig.path='fig_path/'",
('R', {'name': 'plot_1', 'dpi': 72, 'fig.path': 'fig_path/'})),
('r plot_1, bool=TRUE, fig.path="fig_path/"',
('R', {'name': 'plot_1', 'bool': True,
'fig.path': "'fig_path/'"})),
'fig.path': 'fig_path/'})),
('r echo=FALSE',
('R', {'tags': ['remove_input']})),
('r plot_1, echo=TRUE',
('R', {'name': 'plot_1', 'echo': True})),
('python echo=if a==5 then TRUE else FALSE',
('python', {'echo': 'if a==5 then TRUE else FALSE'})),
('python', {'echo': '#R_CODE#if a==5 then TRUE else FALSE'})),
('python noname, tags=c("a", "b", "c"), echo={sum(a+c(1,2))>1}',
('python', {'name': 'noname', 'tags': ['a', 'b', 'c'],
'echo': '{sum(a+c(1,2))>1}'})),
'echo': '#R_CODE#{sum(a+c(1,2))>1}'})),
('python active="ipynb,py"',
('python', {'active': 'ipynb,py'})),
('python include=FALSE, active="Rmd"',
Expand Down
24 changes: 22 additions & 2 deletions tests/test_read_simple_rmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def test_read_mostly_py_rmd_file(rmd="""---
ls()
```

```{r, results='asis', magic_args='-i x'}
```{r, results="asis", magic_args="-i x"}
cat(stringi::stri_rand_lipsum(3), sep='\n\n')
```
"""):
Expand All @@ -49,7 +49,7 @@ def test_read_mostly_py_rmd_file(rmd="""---
'source': '%%R\nls()',
'outputs': []},
{'cell_type': 'code',
'metadata': {'results': "'asis'"},
'metadata': {'results': 'asis'},
'execution_count': None,
'source': "%%R -i x\ncat(stringi::"
"stri_rand_lipsum(3), sep='\n\n')",
Expand Down Expand Up @@ -99,3 +99,23 @@ def test_tags_in_rmd(rmd='''---
''', nb=new_notebook(cells=[new_code_cell('p = 1', metadata={'tags': ['parameters']})])):
nb2 = jupytext.reads(rmd, 'Rmd')
compare_notebooks(nb2, nb)


def round_trip_cell_metadata(cell_metadata):
nb = new_notebook(metadata={'jupytext': {'main_language': 'python'}},
cells=[new_code_cell('1 + 1', metadata=cell_metadata)])
text = jupytext.writes(nb, 'Rmd')
nb2 = jupytext.reads(text, 'Rmd')
compare_notebooks(nb2, nb)


def test_comma_in_metadata(cell_metadata={'a': 'b, c'}):
round_trip_cell_metadata(cell_metadata)


def test_dict_in_metadata(cell_metadata={'a': {'b': 'c'}}):
round_trip_cell_metadata(cell_metadata)


def test_list_in_metadata(cell_metadata={'d': ['e']}):
round_trip_cell_metadata(cell_metadata)