Skip to content

Percent scripts: accept raw-string (r""") and '''-delimited markdown cells, as jupytext writes them #14850

Description

@fqueiro

Description

Quarto renders Python percent scripts and the docs name jupytext as the reference implementation of the format, with markdown cells written either as # comments or as a multi-line string (""").

Jupytext writes markdown cells as strings when cell_markers = '"""' is set, and since 1.13.0 it prefixes the string with r whenever the cell contains a backslash, so that LaTeX such as \frac is not read as a Python escape sequence (changelog entry for jupytext/jupytext#836; src/jupytext/cell_to_text.py, "Markdown cells that contain a backslash should be encoded as raw strings"; expected output in tests/functional/others/test_raw_strings.py). Its reader accepts """, r""", R""" and the ''' forms (src/jupytext/cell_reader.py).

Quarto's parser recognises only a bare """ line:

// src/core/jupyter/percent.ts, markdownFromJupyterPercentScript
const isTripleQuote = (line: string) => !!line.match(/^"{3,}\s*$/);

so a cell jupytext wrote falls into the comment branch, which only strips a leading #, and both delimiter lines are rendered as prose. The same applies to a cell a user writes as r""" by hand to keep Python from interpreting the backslashes (a plain """ cell containing \xi or \underline is a syntax error in Python, so the raw prefix is the only way to keep such a file importable or runnable).

Minimal example

doc.py:

# %% [markdown]
# ---
# title: "Raw-string markdown cell"
# ---

# %% [markdown]
r"""
# A heading

Display math: $\frac{a}{b}$
"""

quarto render doc.py (1.8.25; the parser is unchanged in 1.10.18, 1.11.3 and main) produces a document whose body, as plain text, reads

r”“” A heading
Display math: \(\frac{a}{b}\) ““”

The heading is lost (the # was stripped as a comment prefix) and both delimiters appear as text, smart-quoted by Pandoc. Replacing r""" by """ renders correctly, which confirms the cause.

Proposed change

Accept an optional r/R prefix on the opening delimiter, and the single-quote form, matching jupytext's reader:

const isTripleQuoteOpen = (line: string) => !!line.match(/^[rR]?("{3,}|'{3,})\s*$/);
const isTripleQuoteClose = (line: string) => !!line.match(/^("{3,}|'{3,})\s*$/);

No other part of the pipeline is affected: the cell content is taken as markdown source either way.

Quarto version

1.8.25 on Windows 11; the relevant code is identical at tags v1.10.18 and v1.11.3 and on main.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    engines-jupyterAnything related to Jupyter engineenhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions